bfg-common 1.3.174 → 1.3.176

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.
@@ -1,1576 +1,1579 @@
1
- <template>
2
- <div class="relative" style="display: flex">
3
- <div
4
- :id="outerWrapper"
5
- :class="[
6
- 'datagrid-outer-wrapper',
7
- {
8
- 'datagrid-outer-wrapper-opened-info': isShowHiddenInfo,
9
- },
10
- ]"
11
- >
12
- <div class="datagrid-inner-wrapper">
13
- <div
14
- v-if="props.isMainFilter"
15
- class="main-filter-content flex-justify-end"
16
- >
17
- <atoms-the-icon class="filter-icon" name="filter" />
18
- <input
19
- v-model.trim="mainFilter"
20
- :id="`${props.testId}-main-filter-input`"
21
- :placeholder="props.mainFilterPlaceholder"
22
- type="text"
23
- @input="emits('main-filter', mainFilter)"
24
- />
25
- </div>
26
- <div
27
- :class="[
28
- 'datagrid',
29
- {
30
- 'datagrid-opened-info': isShowHiddenInfo,
31
- },
32
- ]"
33
- >
34
- <div :id="tableWrapperId" class="datagrid-table-wrapper">
35
- <div class="datagrid-table">
36
- <div class="datagrid-header">
37
- <div class="datagrid-row">
38
- <div class="datagrid-row-master datagrid-row-flex">
39
- <div
40
- v-if="props.type || $slots.toggleBlock"
41
- class="datagrid-row-sticky"
42
- >
43
- <div
44
- v-if="props.type"
45
- :id="expandableCaret"
46
- class="datagrid-column datagrid-expandable-caret datagrid-fixed-column flex-align-center flex-justify-center"
47
- >
48
- <template v-if="props.type === 'checkbox'">
49
- <div
50
- class="clr-checkbox-wrapper flex-align-center flex-justify-center w-100"
51
- >
52
- <input
53
- :id="`${props.testId}-${inputId}-all`"
54
- v-model="selectedAll"
55
- type="checkbox"
56
- class="checkbox-btn"
57
- :value="-1"
58
- @change="changeAll"
59
- />
60
- <label
61
- :for="`${props.testId}-${inputId}-all`"
62
- class="clr-control-label"
63
- />
64
- </div>
65
- <div class="datagrid-column-separator"></div>
66
- </template>
67
- </div>
68
- <div
69
- v-if="$slots.toggleBlock"
70
- class="datagrid-toggle-block datagrid-column datagrid-fixed-width"
71
- >
72
- <div class="datagrid-column-flex">
73
- <div class="datagrid-column-separator">
74
- <span class="clr-sr-only" />
75
- <div class="datagrid-column-resize-tracker" />
76
- </div>
77
- </div>
78
- </div>
79
- </div>
80
- <div class="datagrid-row-scrollable">
81
- <div
82
- v-for="(item, key) in headItemsPresent"
83
- :key="key"
84
- :style="{
85
- width: columnsWidth[key][0],
86
- minWidth: columnsWidth[key][1],
87
- }"
88
- class="datagrid-column datagrid-fixed-width"
89
- >
90
- <div class="datagrid-column-flex">
91
- <button
92
- :id="`${props.testId}-sort-column-${key}`"
93
- :class="[
94
- 'datagrid-column-title',
95
- {
96
- 'default text-decoration-none':
97
- !item.sortColumn,
98
- },
99
- ]"
100
- @click="sortTable(item.sortColumn)"
101
- >
102
- <slot :key="key" name="th" :item="item">
103
- <span
104
- :title="item.text"
105
- :style="{
106
- width:
107
- columnsWidth[key][0]?.slice(0, -2) -
108
- (item.hasFilter ? 65 : 40) +
109
- 'px',
110
- }"
111
- class="title-column"
112
- >
113
- {{ item.text }}
114
- </span>
115
- </slot>
116
- <span
117
- v-if="item.sortColumn"
118
- class="sort-arrow-wrap"
119
- >
120
- <atoms-the-icon
121
- v-show="sortInfo[0] === item.sortColumn"
122
- :class="['sort-arrow', { down: sortInfo[1] }]"
123
- name="sort-arrow"
124
- />
125
- </span>
126
- </button>
127
- <button
128
- v-if="item.hasFilter"
129
- :id="`${props.testId}-filter-icon-${key}`"
130
- class="datagrid-filter-toggle clr-anchor clr-smart-open-close"
131
- @click="filterShow[key] = !filterShow[key]"
132
- >
133
- <atoms-the-icon
134
- v-if="filterTerm[key]"
135
- class="filter-icon"
136
- name="filter-solid"
137
- style="fill: #0079b8"
138
- />
139
- <atoms-the-icon
140
- v-else
141
- class="filter-icon"
142
- name="filter"
143
- />
144
- </button>
145
- <atoms-popup-simple-popup
146
- v-model="filterShow[key]"
147
- :test-id="`${props.testId}-filter`"
148
- top="100%"
149
- :left="key === 0 ? '0' : ''"
150
- :right="key !== 0 ? '0' : ''"
151
- >
152
- <input
153
- :id="`${props.testId}-filter-input-${key}`"
154
- v-model="filterTerm[key]"
155
- type="text"
156
- @input="filtering"
157
- />
158
- </atoms-popup-simple-popup>
159
- <div
160
- v-show="
161
- !isShowHiddenInfo ||
162
- (isShowHiddenInfo && key === 0)
163
- "
164
- :class="[
165
- 'datagrid-column-separator',
166
- {
167
- 'double-arrow-separator':
168
- key === 0 && props.withInfo,
169
- },
170
- ]"
171
- @mousedown="setGrab(key, $event)"
172
- >
173
- <button
174
- :id="`${props.testId}-resize-tracker-${key}`"
175
- class="datagrid-column-handle drag-handle draggable"
176
- />
177
- <span class="clr-sr-only" />
178
- <div class="datagrid-column-resize-tracker" />
179
- </div>
180
- </div>
181
- </div>
182
- </div>
183
- </div>
184
- </div>
185
- </div>
186
-
187
- <template v-if="bodyItemsPresent.length">
188
- <div
189
- v-for="(item, key) in bodyItemsPresent"
190
- :key="item.id"
191
- :class="[
192
- 'datagrid-body-row datagrid-row animation',
193
- {
194
- 'datagrid-selected active':
195
- !props.withInfo && checkIsSelectedRow(item[0].id),
196
- 'datagrid-selected-info':
197
- props.withInfo &&
198
- isShowHiddenInfo &&
199
- checkIsSelectedRow(item[0].id),
200
- },
201
- ]"
202
- :[props.rowAttributeIdName]="item[0].dataId"
203
- >
204
- <div>
205
- <div
206
- class="datagrid-row-master datagrid-row-flex"
207
- @click.stop="selectRowById(item[0])"
208
- >
209
- <div
210
- v-if="props.type || $slots.toggleBlock"
211
- class="datagrid-row-sticky"
212
- @click.stop
213
- >
214
- <div
215
- :id="expandableCaret"
216
- :class="[
217
- 'datagrid-expandable-caret flex-justify-center datagrid-cell',
218
- {
219
- 'datagrid-fixed-column': !props.withInfo,
220
- 'datagrid-fixed-column-without-separator':
221
- props.withInfo,
222
- },
223
- ]"
224
- >
225
- <!--TODO refactoring (duplicate)-->
226
- <div
227
- v-if="$slots.toggleBlock && !props.type"
228
- class="datagrid-cell datagrid-fixed-width"
229
- >
230
- <div class="flex-align-center">
231
- <button
232
- :id="`${props.testId}-toggle-icon-${key}`"
233
- class="datagrid-expandable-caret-button reset-btn"
234
- @click="toggle(key)"
235
- >
236
- <atoms-the-icon
237
- :class="[
238
- 'datagrid-expandable-caret-icon',
239
- { toggle: toggedItems[key] },
240
- ]"
241
- name="angle"
242
- />
243
- </button>
244
- </div>
245
- </div>
246
- <slot
247
- v-if="props.type"
248
- :key="key"
249
- name="type"
250
- :item="item"
251
- >
252
- <div
253
- :class="
254
- item[0]?.disabled && 'clr-form-control-disabled'
255
- "
256
- >
257
- <div
258
- :class="`clr-${props.type}-wrapper flex-justify-center flex-align-center`"
259
- >
260
- <input
261
- :id="`${props.testId}-${inputId}-${item[0].id}`"
262
- :key="item[0].id"
263
- v-model="selectedRowLocal"
264
- :type="props.type"
265
- :class="`${props.type}-btn`"
266
- :value="item[0].id"
267
- :disabled="item[0]?.disabled || false"
268
- name="selected-store"
269
- @change="
270
- changeSelectedRow($event, item[0].id)
271
- "
272
- />
273
- <label
274
- :for="`${props.testId}-${inputId}-${item[0].id}`"
275
- class="clr-control-label"
276
- />
277
- </div>
278
- </div>
279
- </slot>
280
- </div>
281
- <!--TODO refactoring (duplicate)-->
282
- <div
283
- v-if="$slots.toggleBlock && props.type"
284
- class="datagrid-cell datagrid-fixed-width"
285
- >
286
- <div class="flex-align-center">
287
- <button
288
- :id="`${props.testId}-toggle-icon-${key}`"
289
- class="datagrid-expandable-caret-button reset-btn"
290
- @click="toggle(key)"
291
- >
292
- <atoms-the-icon
293
- :class="[
294
- 'datagrid-expandable-caret-icon',
295
- { toggle: toggedItems[key] },
296
- ]"
297
- name="angle"
298
- />
299
- </button>
300
- </div>
301
- </div>
302
- </div>
303
- <div class="datagrid-row-scrollable">
304
- <div class="datagrid-scrolling-cells">
305
- <div
306
- v-for="(item2, key2) in item"
307
- v-show="
308
- !isShowHiddenInfo ||
309
- item2.key === 'col1' ||
310
- item2.key === 'icon'
311
- "
312
- :key="key2"
313
- :style="{
314
- width: columnsWidth[key2][0],
315
- minWidth: columnsWidth[key2][1],
316
- }"
317
- :class="[
318
- 'datagrid-cell datagrid-fixed-width',
319
- {
320
- 'hidden-text-triangle':
321
- isShowHiddenInfo &&
322
- item2.data?.name === 'hidden-text-triangle',
323
- },
324
- ]"
325
- >
326
- <div
327
- :class="[
328
- 'flex-align-center h-100',
329
- {
330
- 'double-arrow-width':
331
- item2.data?.name === 'doubleArrows',
332
- },
333
- ]"
334
- >
335
- <div
336
- v-if="item2.data?.name === 'doubleArrows'"
337
- :id="`show-info-${item[0].data.id}`"
338
- :class="[
339
- 'double-arrow-wrap',
340
- {
341
- 'arrow-selected':
342
- isShowHiddenInfo &&
343
- item2.id === selectedRow,
344
- },
345
- ]"
346
- @click.prevent.stop="
347
- doubleArrowClick(item2, item)
348
- "
349
- >
350
- <atoms-the-icon
351
- v-if="item2.data?.name === 'doubleArrows'"
352
- name="doubleArrows"
353
- :class="[
354
- 'double-arrow',
355
- {
356
- 'arrow-selected':
357
- isShowHiddenInfo &&
358
- item2.id === selectedRow,
359
- },
360
- ]"
361
- />
362
- </div>
363
- <span
364
- v-if="item2.text && item2.data?.iconClassName"
365
- class="vertical-divider"
366
- />
367
- <slot :name="item2.key" :item="item2">
368
- <span class="text-ellipsis" :title="item2.text"
369
- >{{ item2.text }}
370
- </span>
371
- </slot>
372
- </div>
373
- </div>
374
- </div>
375
- <div
376
- v-show="toggedItems[key]"
377
- class="datagrid-row-flex datagrid-row-detail datagrid-container"
378
- >
379
- <slot name="toggleBlock" :item="item" />
380
- </div>
381
- </div>
382
- </div>
383
- </div>
384
- </div>
385
- </template>
386
- <template v-else>
387
- <div class="datagrid-placeholder-container">
388
- <div class="datagrid-placeholder datagrid-empty">
389
- <div class="datagrid-placeholder-image"></div>
390
-
391
- <span>No items found</span>
392
- </div>
393
- </div>
394
- </template>
395
- </div>
396
- </div>
397
- </div>
398
-
399
- <div
400
- v-if="!hideFooter"
401
- :class="[
402
- 'datagrid-footer',
403
- {
404
- 'datagrid-footer-opened-info': isShowHiddenInfo,
405
- },
406
- ]"
407
- >
408
- <div
409
- v-if="props.type === 'checkbox' && props.selectedRow?.length"
410
- class="clr-form-control-disabled"
411
- >
412
- <div class="clr-checkbox-wrapper">
413
- <input
414
- :id="`${props.testId}-check-all`"
415
- type="checkbox"
416
- checked
417
- />
418
- <label class="clr-control-label">
419
- {{ props.selectedRow?.length }}
420
- </label>
421
- </div>
422
- </div>
423
- <div class="datagrid-footer-description flex-align-center">
424
- <atoms-table-data-grid-column-switch
425
- v-if="columnKeysLocal"
426
- v-model:column-keys="columnKeysLocal"
427
- :test-id="`${props.testId}-footer-description`"
428
- class="switch-icon"
429
- />
430
-
431
- <div v-if="$slots.action" class="datagrid-footer__action">
432
- <slot name="action" />
433
- </div>
434
- </div>
435
-
436
- <atoms-table-data-grid-pagination
437
- test-id="props.testId"
438
- :page-size="props.pageSize"
439
- :page="props.page"
440
- :options="mergeOptions"
441
- :total-items="props.totalItems"
442
- :total-pages="props.totalPages"
443
- :hide-pagination="props.hidePagination"
444
- :hide-page-size="props.hidePageSize"
445
- :show-page-info="props.showPageInfo"
446
- :page-items-count="props.bodyItems.length"
447
- :is-show-hidden-info="isShowHiddenInfo"
448
- @change-page-size="changePageSize"
449
- @change-page="changePage"
450
- />
451
- </div>
452
-
453
- <atoms-loader v-show="props.loading" class="datagrid-spinner" />
454
- </div>
455
- </div>
456
- <div
457
- v-if="isShowInfo"
458
- id="hidden-features"
459
- :class="[
460
- 'hidden-features',
461
- {
462
- 'show-hidden-info': isShowHiddenInfo,
463
- },
464
- ]"
465
- >
466
- <div class="header">
467
- <slot name="hiddenInfoHeader" :item="showedInfoCol" />
468
- <button
469
- :id="`${props.testId}-hidden-info-toggle-icon-${showedInfoRow?.key}-${showedInfoRow?.data.name}`"
470
- class="signpost-action close"
471
- @click="isShowHiddenInfo = false"
472
- >
473
- <atoms-the-icon class="close-icon" name="close" />
474
- </button>
475
- </div>
476
- <slot name="hiddenInfoBody" />
477
- </div>
478
- </div>
479
- </template>
480
-
481
- <script setup lang="ts">
482
- import { UI_I_HTMLSelectElement } from '~/lib/models/interfaces'
483
- import { itemsPerPage } from '~/components/atoms/table/dataGrid/lib/config/itemsPerPage'
484
- import {
485
- UI_I_HeadItem,
486
- UI_I_BodyItem,
487
- UI_I_ColumnKey,
488
- } from '~/components/atoms/table/dataGrid/lib/models/interfaces'
489
- import { UI_I_OptionItem } from '~/components/atoms/lib/models/interfaces'
490
- import {
491
- UI_T_ColumnKeys,
492
- UI_T_DataGridType,
493
- UI_T_SelectedRow,
494
- } from '~/components/atoms/table/dataGrid/lib/models/types'
495
-
496
- const props = withDefaults(
497
- defineProps<{
498
- headItems: UI_I_HeadItem[]
499
- bodyItems: UI_I_BodyItem[][]
500
- pageSize: number
501
- page: number
502
- totalItems: number
503
- totalPages: number
504
- loading?: boolean
505
- columnKeys?: UI_I_ColumnKey[]
506
- selectedRow?: UI_T_SelectedRow
507
- type?: UI_T_DataGridType
508
- itemsPerPage?: UI_I_OptionItem[]
509
- offSelectByRow?: boolean
510
- hidePageSize?: boolean
511
- showPageInfo?: boolean
512
- serverOff?: boolean
513
- fillWidth?: boolean
514
- hideFooter?: boolean
515
- hidePagination?: boolean
516
- testId?: string
517
- withInfo?: boolean
518
- rowAttributeIdName?: string
519
- isMainFilter?: boolean
520
- mainFilterPlaceholder?: string
521
- }>(),
522
- {
523
- columnKeys: undefined,
524
- selectedRow: undefined,
525
- type: undefined,
526
- itemsPerPage: undefined,
527
- fillWidth: true,
528
- testId: 'ui-data-grid',
529
- withInfo: false,
530
- rowAttributeIdName: 'data-id',
531
- }
532
- )
533
-
534
- const emits = defineEmits<{
535
- (event: 'update:column-keys', value: UI_T_ColumnKeys): void
536
- (event: 'update:selected-row', value: UI_T_SelectedRow): void
537
- (event: 'update:page-size', value: number): void
538
- (event: 'update:page', value: number): void
539
- (event: 'main-filter', value: string): void
540
- (event: 'filtering', value: string[][]): void
541
- (event: 'sorting', value: [string, boolean]): void
542
- (event: 'change', value: any): void
543
- (event: 'row-detail', value: number): void
544
- }>()
545
-
546
- const mainFilter = ref<string>('')
547
-
548
- const mergeOptions = computed<UI_I_OptionItem[]>(
549
- () => props.itemsPerPage || itemsPerPage
550
- )
551
-
552
- const inputId = ref<string>(`radio-input-${useUniqueId()}`)
553
-
554
- const columnKeysLocal = computed<UI_T_ColumnKeys>({
555
- get() {
556
- return props.columnKeys
557
- },
558
- set(newValue) {
559
- emits('update:column-keys', newValue)
560
- },
561
- })
562
-
563
- const selectedAll = ref<boolean>(false)
564
- const changeAll = (e: UI_I_HTMLSelectElement): void => {
565
- const newSelectedRow: (number | string)[] = []
566
- if (e.target.checked) {
567
- bodyItemsPresent.value.forEach((row) => {
568
- if (row[0]?.disabled) return
569
-
570
- newSelectedRow.push(row[0].id)
571
- })
572
- }
573
-
574
- emits('update:selected-row', newSelectedRow)
575
- }
576
-
577
- const selectedRowLocal = ref<UI_T_SelectedRow>([])
578
- const isShowHiddenInfo = ref<boolean>(false)
579
- const tableWrapperId = `table-wrapper-${useUniqueId()}`
580
- let memoryWidth = '0'
581
-
582
- const showedInfoRow = ref<UI_I_BodyItem | null>(null)
583
- const showedInfoCol = ref<UI_I_BodyItem[] | null>(null)
584
-
585
- const isShowInfo = computed(
586
- () =>
587
- showedInfoRow.value &&
588
- showedInfoRow.value.id === props.selectedRow &&
589
- !showedInfoRow.value.data?.text &&
590
- isShowHiddenInfo.value
591
- )
592
-
593
- const setShowedInfoData = (
594
- item: UI_I_BodyItem | null,
595
- items: UI_I_BodyItem[] | null,
596
- reset: boolean = false
597
- ): void => {
598
- showedInfoRow.value = item
599
- showedInfoCol.value = items
600
-
601
- reset && (isShowHiddenInfo.value = false)
602
- item && selectRowById(item)
603
- reset && (isShowHiddenInfo.value = true)
604
- }
605
-
606
- const doubleArrowClick = (
607
- item: UI_I_BodyItem,
608
- items: UI_I_BodyItem[]
609
- ): void => {
610
- if (!isShowHiddenInfo.value) {
611
- setShowedInfoData(item, items)
612
- } else {
613
- if (showedInfoRow.value?.id !== item.id) {
614
- setShowedInfoData(item, items, true)
615
-
616
- return
617
- } else {
618
- setShowedInfoData(null, null)
619
- }
620
- }
621
-
622
- isShowHiddenInfo.value = !isShowHiddenInfo.value
623
- }
624
-
625
- watch(
626
- () => props.selectedRow,
627
- (newValue) => {
628
- if (newValue === undefined) return
629
-
630
- if (Array.isArray(newValue) && !newValue.length) selectedAll.value = false
631
-
632
- selectedRowLocal.value = newValue
633
- },
634
- { immediate: true }
635
- )
636
- const selectRowById = (item: UI_I_BodyItem): void => {
637
- const { id, disabled } = item
638
-
639
- if (props.offSelectByRow || isShowHiddenInfo.value || disabled) return
640
-
641
- if (props.type === 'checkbox' && Array.isArray(selectedRowLocal.value)) {
642
- const has = selectedRowLocal.value.includes(id)
643
- if (has) {
644
- selectedRowLocal.value = selectedRowLocal.value.filter(
645
- (rowId: string | number) => rowId !== id
646
- )
647
- } else {
648
- selectedRowLocal.value.push(id)
649
- }
650
-
651
- emits('change', selectedRowLocal.value)
652
- emits('update:selected-row', selectedRowLocal.value)
653
-
654
- changeSelectedAll(!has)
655
- return
656
- }
657
-
658
- emits('change', id)
659
- emits('update:selected-row', id)
660
- }
661
- const changeSelectedRow = (
662
- e: UI_I_HTMLSelectElement,
663
- id: number | string
664
- ): void => {
665
- if (props.type === 'checkbox' && Array.isArray(selectedRowLocal.value)) {
666
- const newSelectedRow = [...selectedRowLocal.value]
667
- emits('change', newSelectedRow)
668
- emits('update:selected-row', newSelectedRow)
669
-
670
- changeSelectedAll(e.target.checked)
671
- return
672
- }
673
-
674
- emits('change', id)
675
- emits('update:selected-row', id)
676
- }
677
- const changeSelectedAll = (checked: boolean): void => {
678
- if (props.type === 'checkbox' && Array.isArray(selectedRowLocal.value)) {
679
- const newSelectedRow = [...selectedRowLocal.value]
680
-
681
- if (!checked) {
682
- selectedAll.value = false
683
- } else if (newSelectedRow.length === bodyItemsPresent.value.length) {
684
- selectedAll.value = true
685
- }
686
- }
687
- }
688
-
689
- const checkIsSelectedRow = (id: number | string): boolean => {
690
- if (props.type === 'checkbox' && Array.isArray(props.selectedRow)) {
691
- return props.selectedRow.includes(id)
692
- }
693
- return props.selectedRow === id
694
- }
695
-
696
- // Sorting
697
- const sortInfo = ref<[string, boolean]>(['', true])
698
- const sortedColumnIndex = computed<number>(() => {
699
- let index = -1
700
- headItemsPresent.value.forEach((item, key) => {
701
- if (item.sortColumn === sortInfo.value[0]) index = key
702
- })
703
-
704
- return index
705
- })
706
- const sortTable = (sortName: string): void => {
707
- if (!sortName) return
708
-
709
- emits('update:selected-row', selectedRowLocal.value)
710
-
711
- if (sortInfo.value[0] === sortName) {
712
- sortInfo.value[1] = !sortInfo.value[1]
713
-
714
- emits('sorting', sortInfo.value)
715
- return
716
- }
717
- sortInfo.value[0] = sortName
718
- sortInfo.value[1] = true
719
-
720
- emits('sorting', sortInfo.value)
721
- }
722
-
723
- // Filtering
724
- const filterShow = ref<boolean[]>([])
725
- const filterTerm = ref<string[]>([])
726
- const filtering = (): void => {
727
- const filter: string[][] = []
728
- headItemsPresent.value.forEach((item, key) => {
729
- if (filterTerm.value[key]) filter.push([item.key, filterTerm.value[key]])
730
- })
731
-
732
- emits('filtering', filter)
733
- }
734
-
735
- // Pagination
736
- const changePageSize = (value: number): void => {
737
- emits('update:page-size', value)
738
- }
739
- const changePage = (value: number): void => {
740
- emits('update:page', value)
741
- }
742
-
743
- const headItemsPresent = computed<UI_I_HeadItem[]>(() => {
744
- if (!columnKeysLocal.value) {
745
- return props.headItems
746
- }
747
-
748
- return props.headItems.filter((item, key) => {
749
- return columnKeysLocal.value?.find(
750
- (item2, key2) => item2.key === item.key && key === key2
751
- )?.show
752
- })
753
- })
754
-
755
- const bodyItemsPresent = computed<UI_I_BodyItem[][]>(() => {
756
- let items: UI_I_BodyItem[][] = props.bodyItems
757
-
758
- // Filtering by column
759
- if (columnKeysLocal.value) {
760
- items = items.map((arr) => {
761
- arr = arr.filter((item, key) => {
762
- return columnKeysLocal.value?.find(
763
- (item2, key2) => item2.key === item.key && key === key2
764
- )?.show
765
- })
766
- return arr
767
- })
768
- }
769
-
770
- if (props.serverOff) {
771
- // Sorting
772
- if (sortInfo.value[0] !== '') {
773
- items = useDeepCopy(items).sort(
774
- (a: UI_I_BodyItem[], b: UI_I_BodyItem[]) => {
775
- let first = a[sortedColumnIndex.value].text.toString().toLowerCase()
776
- let second = b[sortedColumnIndex.value].text.toString().toLowerCase()
777
-
778
- const sortValueA = a[sortedColumnIndex.value]?.data?.sortValue
779
- const sortValueB = b[sortedColumnIndex.value]?.data?.sortValue
780
- if (sortValueA || sortValueA === 0) {
781
- first = sortValueA
782
- }
783
- if (sortValueB || sortValueB === 0) {
784
- second = sortValueB
785
- }
786
-
787
- if (sortInfo.value[1]) {
788
- return first > second ? 1 : first < second ? -1 : 0
789
- } else {
790
- return first < second ? 1 : first > second ? -1 : 0
791
- }
792
- }
793
- )
794
- }
795
- // Filtering
796
- const hasFilter = headItemsPresent.value.some(
797
- (_, key) => filterTerm.value[key]
798
- )
799
- if (hasFilter) {
800
- items = items.filter((row) => {
801
- // 0 - начальное значение
802
- // 1 - найден элемент
803
- // -1 - ненайден элемент
804
- let hasItem = 0
805
- headItemsPresent.value.forEach((item, key) => {
806
- if (!filterTerm.value[key]) return
807
- const term = filterTerm.value[key].toLowerCase()
808
-
809
- row.forEach((col) => {
810
- if (
811
- col.key === item.key &&
812
- typeof col.text === 'string' &&
813
- hasItem != -1
814
- ) {
815
- hasItem = col.text.toLowerCase().includes(term) ? 1 : -1
816
- }
817
- })
818
- })
819
-
820
- return hasItem === 1
821
- })
822
- }
823
- }
824
-
825
- return items
826
- })
827
-
828
- const toggedItems = ref<boolean[]>([])
829
-
830
- const toggle = (key: number): void => {
831
- toggedItems.value[key] = !toggedItems.value[key]
832
- if (!toggedItems.value[key]) return
833
- emits('row-detail', key)
834
- }
835
-
836
- const outerWrapper = `datagrid-outer-wrapper${useUniqueId()}`
837
- const expandableCaret = `datagrid-expandable-caret${useUniqueId()}`
838
-
839
- // Resize
840
- let helper = false
841
- let setColumnWidth = (): void => {
842
- if (!helper) {
843
- columnsWidth.value = []
844
- headItemsPresent.value.forEach((item) => {
845
- columnsWidth.value.push([
846
- item.width, // width
847
- item.width, // min-width
848
- ])
849
- })
850
-
851
- helper = true
852
- setTimeout(() => setColumnWidth(), 0)
853
- return
854
- }
855
- // Не продолжаем, чтобы ширина калонок была так как заданно в headItemsPresent
856
- if (!props.fillWidth) return
857
-
858
- const dataGridWidth = document.getElementById(outerWrapper)?.clientWidth || 0
859
- const leftColumnWidth =
860
- document.getElementById(expandableCaret)?.clientWidth || 0
861
- const bordersWidth = 2
862
- const columnWidth =
863
- (dataGridWidth - leftColumnWidth - bordersWidth) /
864
- headItemsPresent.value.length
865
-
866
- headItemsPresent.value.forEach((item) => {
867
- columnsWidth.value.push([
868
- `${columnWidth}px`, // width
869
- item.width, // min-width
870
- ])
871
- })
872
- }
873
- setColumnWidth = useThrottle(setColumnWidth)
874
-
875
- const columnsWidth = ref<[string, string][]>([])
876
- watch(
877
- bodyItemsPresent,
878
- (newValue: UI_I_BodyItem[][]) => {
879
- newValue.forEach(() => {
880
- toggedItems.value.push(false)
881
- })
882
- setColumnWidth()
883
- },
884
- {
885
- immediate: true,
886
- deep: true,
887
- }
888
- )
889
-
890
- watch(
891
- headItemsPresent,
892
- (newValue: UI_I_HeadItem[]) => {
893
- filterShow.value = newValue.map(() => false)
894
- filterTerm.value = newValue.map(() => '')
895
- },
896
- {
897
- immediate: true,
898
- deep: true,
899
- }
900
- )
901
-
902
- const grabColumn = ref<number>(-1)
903
- const grabStartX = ref<number>(0)
904
- const setGrab = (key: number, e: MouseEvent): void => {
905
- if (props.withInfo && key === 0) return
906
-
907
- if (!isShowHiddenInfo.value) {
908
- grabColumn.value = key
909
- const currentWidth = parseInt(columnsWidth.value[grabColumn.value][0])
910
- grabStartX.value = e.clientX - currentWidth
911
- }
912
- }
913
-
914
- const isDrag = ref<boolean>(false)
915
-
916
- const mouseup = (): void => {
917
- if (grabColumn.value === -1) {
918
- return
919
- }
920
-
921
- grabColumn.value = -1
922
- isDrag.value = false
923
- }
924
-
925
- let resizeObserve: ResizeObserver
926
- let mousemove = (e: MouseEvent): void => {
927
- if (grabColumn.value === -1) return
928
-
929
- e.preventDefault()
930
- isDrag.value = true
931
- resizeObserve.disconnect()
932
-
933
- const minWidth = parseInt(columnsWidth.value[grabColumn.value][1])
934
- const changeX = Math.max(e.clientX - grabStartX.value, minWidth)
935
-
936
- columnsWidth.value[grabColumn.value] = [`${changeX}px`, `${minWidth}px`]
937
- }
938
- mousemove = useThrottle(mousemove)
939
-
940
- const setResizeObserve = (): void => {
941
- const el = document.getElementById(outerWrapper)
942
-
943
- if (!el) {
944
- setTimeout(setResizeObserve, 0)
945
- return
946
- }
947
-
948
- resizeObserve = new ResizeObserver(setColumnWidth)
949
- resizeObserve.observe(el)
950
- }
951
-
952
- let resizeObserveWithInfo: ResizeObserver
953
-
954
- const setColumnWidthWithInfo = (ent: ResizeObserverEntry[]): void => {
955
- if (isShowHiddenInfo.value) {
956
- memoryWidth = columnsWidth.value[1][0]
957
- columnsWidth.value[1][0] = `${ent[0].contentBoxSize[0].inlineSize - 86}px`
958
- } else {
959
- columnsWidth.value[1][0] = memoryWidth
960
- }
961
- }
962
-
963
- const setResizeObserveWithInfo = (): void => {
964
- const el = document.querySelector('.datagrid')
965
-
966
- if (!el) {
967
- setTimeout(setResizeObserveWithInfo, 0)
968
- return
969
- }
970
-
971
- resizeObserveWithInfo = new ResizeObserver(setColumnWidthWithInfo)
972
- resizeObserveWithInfo.observe(el)
973
- }
974
-
975
- onMounted(() => {
976
- window.addEventListener('mousemove', mousemove)
977
- window.addEventListener('mouseup', mouseup)
978
-
979
- if (props.withInfo) {
980
- setResizeObserveWithInfo()
981
- }
982
-
983
- setResizeObserve()
984
- })
985
- onUnmounted(() => {
986
- window.removeEventListener('mouseup', mouseup)
987
- window.removeEventListener('mousemove', mousemove)
988
- })
989
- </script>
990
-
991
- <style scoped lang="scss">
992
- @import '~/assets/scss/common/mixins';
993
- .datagrid-outer-wrapper {
994
- @include flex($dir: row);
995
- padding-top: 12px;
996
- flex-grow: 1;
997
- overflow: auto;
998
-
999
- &.datagrid-outer-wrapper-opened-info {
1000
- width: 35%;
1001
- min-width: 195px;
1002
- }
1003
-
1004
- & * {
1005
- box-sizing: border-box;
1006
- }
1007
-
1008
- & svg {
1009
- fill: var(--table-color);
1010
- }
1011
-
1012
- .datagrid-inner-wrapper {
1013
- @include flex($dir: column);
1014
- flex-grow: 1;
1015
- overflow: auto;
1016
-
1017
- .main-filter-content {
1018
- align-items: center;
1019
-
1020
- .filter-icon {
1021
- width: 16px;
1022
- height: 16px;
1023
- margin-right: 10px;
1024
- }
1025
- }
1026
- .datagrid {
1027
- overflow: auto;
1028
- flex: 1 1 auto;
1029
- border-radius: 0.125rem 0.125rem 0 0;
1030
- background-color: var(--block-view-bg-color);
1031
- border-color: var(--global-border-color);
1032
-
1033
- &.datagrid-opened-info {
1034
- border-radius: 0.125rem 0 0 0;
1035
- overflow-x: hidden;
1036
- }
1037
-
1038
- .datagrid-table-wrapper {
1039
- min-width: max-content;
1040
- display: flex;
1041
- flex: 1 1 auto;
1042
- min-height: 100%;
1043
-
1044
- .datagrid-table {
1045
- @include flex($dir: column);
1046
- flex: 1 1 auto;
1047
- align-content: flex-start;
1048
- position: relative;
1049
-
1050
- .datagrid-header {
1051
- position: sticky;
1052
- top: 0;
1053
- z-index: 501;
1054
- width: auto;
1055
-
1056
- .datagrid-row-scrollable {
1057
- flex-direction: row;
1058
-
1059
- .datagrid-column-separator {
1060
- user-select: none;
1061
-
1062
- &::after {
1063
- cursor: col-resize;
1064
- }
1065
- &.double-arrow-separator .datagrid-column-handle {
1066
- cursor: unset;
1067
- }
1068
- &.double-arrow-separator::after {
1069
- cursor: unset;
1070
- }
1071
- }
1072
- }
1073
-
1074
- .datagrid-row {
1075
- color: var(--table-color);
1076
- background-color: var(--block-view-bg-color);
1077
-
1078
- &.datagrid-selected {
1079
- background-color: var(--row-selected-bg-color);
1080
- border-bottom: 1px solid var(--global-border-color);
1081
-
1082
- & :deep(*) {
1083
- color: var(--table-active-color);
1084
- }
1085
- }
1086
-
1087
- .datagrid-column {
1088
- background-color: var(--block-view-bg-color);
1089
- border-bottom: 1px solid var(--global-border-color);
1090
- padding: 6px 12px 5px;
1091
- position: relative;
1092
- //flex: 1 1 auto;
1093
-
1094
- &:last-child {
1095
- flex: 1 1 auto;
1096
- }
1097
-
1098
- &.datagrid-toggle-block {
1099
- width: 38px;
1100
- min-width: 38px;
1101
-
1102
- .datagrid-column-separator {
1103
- cursor: default;
1104
-
1105
- &::after {
1106
- cursor: default;
1107
- }
1108
- }
1109
- }
1110
- }
1111
-
1112
- .datagrid-column-title {
1113
- align-self: auto;
1114
- color: var(--table-color);
1115
- background-color: var(--block-view-bg-color);
1116
- border-bottom-color: var(--global-border-color);
1117
- font-size: 11px;
1118
- @include flex($align: center);
1119
- display: flex;
1120
- flex-direction: row;
1121
- justify-content: flex-start;
1122
- align-items: center;
1123
- //line-height: 24px;
1124
- line-height: normal;
1125
-
1126
- .title-column {
1127
- font-weight: bold;
1128
- font-size: 11px;
1129
- overflow: hidden;
1130
- text-wrap: none;
1131
- text-overflow: ellipsis;
1132
- }
1133
-
1134
- .sort-arrow-wrap {
1135
- margin-left: auto;
1136
- height: 14px;
1137
- width: 14px;
1138
- min-height: 14px;
1139
- min-width: 14px;
1140
- vertical-align: middle;
1141
-
1142
- .sort-arrow {
1143
- &.down {
1144
- transform: rotate(180deg);
1145
- }
1146
- }
1147
- }
1148
- .title-icon {
1149
- width: 24px;
1150
- height: 24px;
1151
- }
1152
- }
1153
-
1154
- .datagrid-filter-toggle {
1155
- background: unset;
1156
- margin-top: -4px;
1157
- align-self: center;
1158
-
1159
- .filter-icon {
1160
- width: 16px;
1161
- height: 16px;
1162
- }
1163
- }
1164
- }
1165
- }
1166
-
1167
- .datagrid-placeholder-container {
1168
- .datagrid-placeholder.datagrid-empty {
1169
- background: var(--block-view-bg-color);
1170
- }
1171
- span {
1172
- font-size: 16px;
1173
- color: var(--global-font-color4);
1174
- }
1175
- }
1176
-
1177
- .datagrid-row {
1178
- width: 100%;
1179
- min-width: max-content;
1180
- border-top: none;
1181
- color: var(--table-color);
1182
- background-color: var(--block-view-bg-color);
1183
- border-bottom: 1px solid var(--global-border-color);
1184
-
1185
- &.datagrid-selected {
1186
- & :deep(*) {
1187
- color: var(--table-active-color);
1188
- }
1189
-
1190
- .datagrid-cell {
1191
- background-color: var(--row-selected-bg-color);
1192
- border-bottom: 1px solid var(--global-border-color);
1193
- position: relative;
1194
- line-height: 1rem;
1195
- }
1196
-
1197
- .datagrid-row-detail {
1198
- background-color: var(--row-selected-bg-color);
1199
- border-bottom: 1px solid var(--global-border-color);
1200
- }
1201
- }
1202
-
1203
- .datagrid-cell {
1204
- min-width: 38px;
1205
- min-height: 28px;
1206
- padding: 2px 12px 3px 12px;
1207
- position: relative;
1208
-
1209
- &:has(.double-arrow-wrap) {
1210
- padding-left: 4px;
1211
- }
1212
-
1213
- &:has(.double-arrow-wrap)::after {
1214
- content: '';
1215
- width: 0.5px;
1216
- height: calc(100% - 6px);
1217
- position: absolute;
1218
- right: 2px;
1219
- top: 3px;
1220
- background-color: var(--global-border-color);
1221
- }
1222
-
1223
- &:last-child {
1224
- flex: 1 1 auto;
1225
- }
1226
-
1227
- button {
1228
- height: 0.9rem;
1229
- width: 0.9rem;
1230
-
1231
- .arrow-icon {
1232
- width: 16px;
1233
- height: 16px;
1234
- transform: rotate(90deg);
1235
- }
1236
- }
1237
-
1238
- .datagrid-cell-icon {
1239
- display: inline-block;
1240
- width: 16px;
1241
- height: 16px;
1242
- }
1243
-
1244
- .datagrid-expandable-caret-button {
1245
- cursor: pointer;
1246
- width: 100%;
1247
-
1248
- .datagrid-expandable-caret-icon {
1249
- width: 16px;
1250
- height: 16px;
1251
- transform: rotate(90deg);
1252
- fill: var(--table-caret-color);
1253
-
1254
- &.toggle {
1255
- transform: rotate(180deg);
1256
- }
1257
- }
1258
- }
1259
- }
1260
-
1261
- &.datagrid-selected-info {
1262
- width: 100%;
1263
- min-width: max-content;
1264
- border-top: none;
1265
- color: var(--table-color);
1266
- background-color: var(--block-view-bg-color);
1267
-
1268
- .datagrid-cell {
1269
- position: relative;
1270
-
1271
- &.hidden-text-triangle::after {
1272
- content: '';
1273
- position: absolute;
1274
- transform: rotate(225deg);
1275
- border-bottom: 15px solid transparent;
1276
- border-right: 15px solid var(--global-bg-color);
1277
- bottom: 26%;
1278
- right: -16px;
1279
- z-index: 1000;
1280
- }
1281
-
1282
- &.hidden-text-triangle::before {
1283
- content: '';
1284
- transform: rotate(-135deg);
1285
- position: absolute;
1286
- border-bottom: 16px solid transparent;
1287
- border-right: 16px solid var(--global-border-color);
1288
- bottom: 23%;
1289
- right: -17px;
1290
- z-index: 999;
1291
- }
1292
- }
1293
- }
1294
- }
1295
-
1296
- .datagrid-row-sticky {
1297
- @include flex($w: nowrap);
1298
- position: sticky;
1299
- left: 0;
1300
- z-index: 500;
1301
- background-color: var(--block-view-bg-color);
1302
-
1303
- .datagrid-column {
1304
- color: var(--table-color);
1305
- background-color: var(--block-view-bg-color);
1306
- border-bottom-color: var(--global-border-color);
1307
- text-align: left;
1308
- display: flex;
1309
- flex: 1 1 auto;
1310
- vertical-align: top;
1311
- border: none;
1312
-
1313
- &.datagrid-expandable-caret {
1314
- .datagrid-column-separator {
1315
- display: block;
1316
-
1317
- &::after {
1318
- top: 0;
1319
- height: 18px;
1320
- }
1321
- }
1322
-
1323
- .radio-btn {
1324
- width: 16px;
1325
- height: 16px;
1326
- }
1327
- }
1328
-
1329
- .datagrid-column-separator {
1330
- position: relative;
1331
- //left: 0.6rem;
1332
- flex: 0 0 auto;
1333
- width: 0.05rem;
1334
- order: 100;
1335
- margin-left: auto;
1336
- height: 100%;
1337
- }
1338
- }
1339
-
1340
- .datagrid-fixed-column-without-separator {
1341
- background-color: var(--block-view-bg-color);
1342
-
1343
- &::after {
1344
- background-color: transparent;
1345
- }
1346
- }
1347
-
1348
- .datagrid-fixed-column {
1349
- background-color: var(--block-view-bg-color);
1350
-
1351
- &::after {
1352
- content: '';
1353
- width: 0.05rem;
1354
- height: calc(100% - 0.5rem);
1355
- position: absolute;
1356
- right: 0;
1357
- top: 0.25rem;
1358
- background-color: var(--global-border-color);
1359
- }
1360
-
1361
- .clr-form-control-disabled {
1362
- .clr-checkbox-wrapper {
1363
- label {
1364
- cursor: not-allowed;
1365
- }
1366
- }
1367
- }
1368
- }
1369
- }
1370
-
1371
- .datagrid-row-scrollable {
1372
- @include flex($ff: row nowrap);
1373
- flex: 1 1 auto;
1374
-
1375
- .datagrid-scrolling-cells {
1376
- @include flex($ff: row nowrap);
1377
- flex: 1 1 auto;
1378
- }
1379
- }
1380
- .datagrid-body-row {
1381
- .datagrid-row-scrollable {
1382
- @include flex($ff: column nowrap);
1383
-
1384
- .datagrid-row-detail {
1385
- flex: 1;
1386
- }
1387
- }
1388
-
1389
- &:not(.datagrid-selected):hover {
1390
- border-bottom: 1px solid var(--table-hover-row-border-color);
1391
- background-color: var(--table-hover-row-background-color);
1392
- color: var(--table-hover-row-color);
1393
-
1394
- .datagrid-fixed-column {
1395
- background-color: var(--table-hover-row-background-color);
1396
- }
1397
- .datagrid-cell {
1398
- background-color: var(--table-hover-row-background-color);
1399
- }
1400
- }
1401
- }
1402
- }
1403
- }
1404
- }
1405
-
1406
- .datagrid-footer {
1407
- flex: 0 0 auto;
1408
- @include flex($ff: row nowrap, $just: space-between, $align: stretch);
1409
- font-size: 0.55rem;
1410
- background-color: var(--block-view-bg-color);
1411
- border: 0.05rem solid var(--global-border-color);
1412
- border-top: none;
1413
- border-radius: 0 0 0.15rem 0.15rem;
1414
- padding: 0 0.6rem;
1415
- height: 28px;
1416
-
1417
- &.datagrid-footer-opened-info {
1418
- border-radius: 0 0 0 0.15rem;
1419
- flex-direction: row-reverse;
1420
- }
1421
-
1422
- .clr-form-control-disabled {
1423
- opacity: 1;
1424
-
1425
- .clr-checkbox-wrapper {
1426
- label {
1427
- color: #8c8c8c;
1428
- margin-right: 9px;
1429
- padding-left: 22px;
1430
- &:before {
1431
- position: absolute;
1432
- top: 4px;
1433
- left: 0;
1434
- content: '';
1435
- display: inline-block;
1436
- height: 16px;
1437
- width: 16px;
1438
- border: none;
1439
- border-radius: 3px;
1440
- background-color: var(--table-checkbox-color);
1441
- }
1442
-
1443
- &:after {
1444
- position: absolute;
1445
- content: '';
1446
- display: inline-block;
1447
- height: 5px;
1448
- width: 8px;
1449
- border-left: 2px solid #fff;
1450
- border-bottom: 2px solid #fff;
1451
- top: 4px;
1452
- left: 4px;
1453
- transform: translateY(4px) rotate(-45deg);
1454
- }
1455
- }
1456
- }
1457
- }
1458
- }
1459
-
1460
- .datagrid-spinner {
1461
- top: 0.6rem;
1462
- height: calc(100% - 0.6rem);
1463
- }
1464
-
1465
- .datagrid-footer-description {
1466
- flex: 1 1 auto;
1467
-
1468
- :deep(svg) {
1469
- fill: var(--table-switch-color);
1470
- }
1471
- }
1472
-
1473
- .clr-radio-wrapper,
1474
- .clr-checkbox-wrapper {
1475
- height: 18px;
1476
- }
1477
-
1478
- .clr-radio-wrapper label,
1479
- .clr-checkbox-wrapper label {
1480
- padding-left: 16px;
1481
- }
1482
- }
1483
- }
1484
- //.vertical-divider {
1485
- // width: 1px;
1486
- // height: 22px;
1487
- // background: #bbb;
1488
- // margin: 2px 2px 0 -5px;
1489
- //}
1490
-
1491
- .hidden-features {
1492
- padding: 9px 14px;
1493
- background-color: var(--global-bg-color);
1494
- color: var(--global-font-color2);
1495
- border: 1px solid var(--global-border-color);
1496
- border-left: none;
1497
- overflow-y: auto;
1498
- overflow-x: hidden;
1499
- width: 65%;
1500
-
1501
- .header {
1502
- display: flex;
1503
- align-items: center;
1504
- justify-content: space-between;
1505
- background-color: inherit;
1506
-
1507
- h3 {
1508
- font-size: 1rem;
1509
- color: var(--global-font-color2) !important;
1510
- line-height: 1.7rem;
1511
- }
1512
- button {
1513
- line-height: 24px;
1514
-
1515
- .close-icon {
1516
- margin-left: 10px;
1517
- width: 24px;
1518
- height: 24px;
1519
- }
1520
- }
1521
- }
1522
- }
1523
- .double-arrow-width {
1524
- width: 25px;
1525
- }
1526
- .double-arrow-wrap {
1527
- width: 30px;
1528
- height: 20px;
1529
- padding-top: 1px;
1530
- padding-left: 5px;
1531
- cursor: pointer;
1532
- background-color: transparent;
1533
-
1534
- .double-arrow {
1535
- background-color: transparent;
1536
- transform: rotate(90deg);
1537
- width: 16px;
1538
- height: 16px;
1539
- }
1540
-
1541
- .double-arrow.arrow-selected {
1542
- transform: rotate(-90deg) !important;
1543
- background-color: #0079b8;
1544
- }
1545
- }
1546
- .double-arrow-wrap.arrow-selected {
1547
- background-color: #0079b8;
1548
- border-radius: 3px;
1549
- }
1550
- </style>
1551
-
1552
- <style>
1553
- :root {
1554
- --table-color: #565656;
1555
- --table-active-color: #fff;
1556
- --table-checkbox-color: #454545;
1557
- --table-caret-color: #454545;
1558
- --table-switch-color: #575757;
1559
- --table-hover-row-border-color: #666;
1560
- --table-hover-row-background-color: #e8e8e8;
1561
- --table-hover-row-color: #454545;
1562
- --table-spinner-bg-color: #ffffff99;
1563
- }
1564
-
1565
- :root.dark-theme {
1566
- --table-color: #fff;
1567
- --table-active-color: #565656;
1568
- --table-checkbox-color: #49aeda;
1569
- --table-caret-color: #ffffff;
1570
- --table-switch-color: #b3b3b3;
1571
- --table-hover-row-border-color: #fff;
1572
- --table-hover-row-background-color: #324f61;
1573
- --table-hover-row-color: #e9ecef;
1574
- --table-spinner-bg-color: rgba(0, 0, 0, 0.5);
1575
- }
1576
- </style>
1
+ <template>
2
+ <div class="relative" style="display: flex">
3
+ <div
4
+ :id="outerWrapper"
5
+ :class="[
6
+ 'datagrid-outer-wrapper',
7
+ {
8
+ 'datagrid-outer-wrapper-opened-info': isShowHiddenInfo,
9
+ },
10
+ ]"
11
+ >
12
+ <div class="datagrid-inner-wrapper">
13
+ <div
14
+ v-if="props.isMainFilter"
15
+ class="main-filter-content flex-justify-end"
16
+ >
17
+ <atoms-the-icon class="filter-icon" name="filter" />
18
+ <input
19
+ v-model.trim="mainFilter"
20
+ :id="`${props.testId}-main-filter-input`"
21
+ :placeholder="props.mainFilterPlaceholder"
22
+ type="text"
23
+ @input="emits('main-filter', mainFilter)"
24
+ />
25
+ </div>
26
+ <div
27
+ :class="[
28
+ 'datagrid',
29
+ {
30
+ 'datagrid-opened-info': isShowHiddenInfo,
31
+ },
32
+ ]"
33
+ >
34
+ <div :id="tableWrapperId" class="datagrid-table-wrapper">
35
+ <div class="datagrid-table">
36
+ <div class="datagrid-header">
37
+ <div class="datagrid-row">
38
+ <div class="datagrid-row-master datagrid-row-flex">
39
+ <div
40
+ v-if="props.type || $slots.toggleBlock"
41
+ class="datagrid-row-sticky"
42
+ >
43
+ <div
44
+ v-if="props.type"
45
+ :id="expandableCaret"
46
+ class="datagrid-column datagrid-expandable-caret datagrid-fixed-column flex-align-center flex-justify-center"
47
+ >
48
+ <template v-if="props.type === 'checkbox'">
49
+ <div
50
+ class="clr-checkbox-wrapper flex-align-center flex-justify-center w-100"
51
+ >
52
+ <input
53
+ :id="`${props.testId}-${inputId}-all`"
54
+ v-model="selectedAll"
55
+ type="checkbox"
56
+ class="checkbox-btn"
57
+ :value="-1"
58
+ @change="changeAll"
59
+ />
60
+ <label
61
+ :for="`${props.testId}-${inputId}-all`"
62
+ class="clr-control-label"
63
+ />
64
+ </div>
65
+ <div class="datagrid-column-separator"></div>
66
+ </template>
67
+ </div>
68
+ <div
69
+ v-if="$slots.toggleBlock"
70
+ class="datagrid-toggle-block datagrid-column datagrid-fixed-width"
71
+ >
72
+ <div class="datagrid-column-flex">
73
+ <div class="datagrid-column-separator">
74
+ <span class="clr-sr-only" />
75
+ <div class="datagrid-column-resize-tracker" />
76
+ </div>
77
+ </div>
78
+ </div>
79
+ </div>
80
+ <div class="datagrid-row-scrollable">
81
+ <div
82
+ v-for="(item, key) in headItemsPresent"
83
+ :key="key"
84
+ :style="{
85
+ width: columnsWidth[key][0],
86
+ minWidth: columnsWidth[key][1],
87
+ }"
88
+ class="datagrid-column datagrid-fixed-width"
89
+ >
90
+ <div class="datagrid-column-flex">
91
+ <button
92
+ :id="`${props.testId}-sort-column-${key}`"
93
+ :class="[
94
+ 'datagrid-column-title',
95
+ {
96
+ 'default text-decoration-none':
97
+ !item.sortColumn,
98
+ },
99
+ ]"
100
+ @click="sortTable(item.sortColumn)"
101
+ >
102
+ <slot :key="key" name="th" :item="item">
103
+ <span
104
+ :title="item.text"
105
+ :style="{
106
+ width:
107
+ columnsWidth[key][0]?.slice(0, -2) -
108
+ (item.hasFilter ? 65 : 40) +
109
+ 'px',
110
+ }"
111
+ class="title-column"
112
+ >
113
+ {{ item.text }}
114
+ </span>
115
+ </slot>
116
+ <span
117
+ v-if="item.sortColumn"
118
+ class="sort-arrow-wrap"
119
+ >
120
+ <atoms-the-icon
121
+ v-show="sortInfo[0] === item.sortColumn"
122
+ :class="['sort-arrow', { down: sortInfo[1] }]"
123
+ name="sort-arrow"
124
+ />
125
+ </span>
126
+ </button>
127
+ <button
128
+ v-if="item.hasFilter"
129
+ :id="`${props.testId}-filter-icon-${key}`"
130
+ class="datagrid-filter-toggle clr-anchor clr-smart-open-close"
131
+ @click="filterShow[key] = !filterShow[key]"
132
+ >
133
+ <atoms-the-icon
134
+ v-if="filterTerm[key]"
135
+ class="filter-icon"
136
+ name="filter-solid"
137
+ style="fill: #0079b8"
138
+ />
139
+ <atoms-the-icon
140
+ v-else
141
+ class="filter-icon"
142
+ name="filter"
143
+ />
144
+ </button>
145
+ <atoms-popup-simple-popup
146
+ v-model="filterShow[key]"
147
+ :test-id="`${props.testId}-filter`"
148
+ top="100%"
149
+ :left="key === 0 ? '0' : ''"
150
+ :right="key !== 0 ? '0' : ''"
151
+ >
152
+ <input
153
+ :id="`${props.testId}-filter-input-${key}`"
154
+ v-model="filterTerm[key]"
155
+ type="text"
156
+ @input="filtering"
157
+ />
158
+ </atoms-popup-simple-popup>
159
+ <div
160
+ v-show="
161
+ !isShowHiddenInfo ||
162
+ (isShowHiddenInfo && key === 0)
163
+ "
164
+ :class="[
165
+ 'datagrid-column-separator',
166
+ {
167
+ 'double-arrow-separator':
168
+ key === 0 && props.withInfo,
169
+ },
170
+ ]"
171
+ @mousedown="setGrab(key, $event)"
172
+ >
173
+ <button
174
+ :id="`${props.testId}-resize-tracker-${key}`"
175
+ class="datagrid-column-handle drag-handle draggable"
176
+ />
177
+ <span class="clr-sr-only" />
178
+ <div class="datagrid-column-resize-tracker" />
179
+ </div>
180
+ </div>
181
+ </div>
182
+ </div>
183
+ </div>
184
+ </div>
185
+ </div>
186
+
187
+ <template v-if="bodyItemsPresent.length">
188
+ <div
189
+ v-for="(item, key) in bodyItemsPresent"
190
+ :key="item.id"
191
+ :class="[
192
+ 'datagrid-body-row datagrid-row animation',
193
+ {
194
+ 'datagrid-selected active':
195
+ !props.withInfo && checkIsSelectedRow(item[0].id),
196
+ 'datagrid-selected-info':
197
+ props.withInfo &&
198
+ isShowHiddenInfo &&
199
+ checkIsSelectedRow(item[0].id),
200
+ },
201
+ ]"
202
+ :[props.rowAttributeIdName]="item[0].dataId"
203
+ >
204
+ <div>
205
+ <div
206
+ class="datagrid-row-master datagrid-row-flex"
207
+ @click.stop="selectRowById(item[0])"
208
+ >
209
+ <div
210
+ v-if="props.type || $slots.toggleBlock"
211
+ class="datagrid-row-sticky"
212
+ @click.stop
213
+ >
214
+ <div
215
+ :id="expandableCaret"
216
+ :class="[
217
+ 'datagrid-expandable-caret flex-justify-center datagrid-cell',
218
+ {
219
+ 'datagrid-fixed-column': !props.withInfo,
220
+ 'datagrid-fixed-column-without-separator':
221
+ props.withInfo,
222
+ },
223
+ ]"
224
+ >
225
+ <!--TODO refactoring (duplicate)-->
226
+ <div
227
+ v-if="$slots.toggleBlock && !props.type"
228
+ class="datagrid-cell datagrid-fixed-width"
229
+ >
230
+ <div
231
+ v-if="item[0]?.isShowToggleIcon ?? true"
232
+ class="flex-align-center"
233
+ >
234
+ <button
235
+ :id="`${props.testId}-toggle-icon-${key}`"
236
+ class="datagrid-expandable-caret-button reset-btn"
237
+ @click="toggle(key)"
238
+ >
239
+ <atoms-the-icon
240
+ :class="[
241
+ 'datagrid-expandable-caret-icon',
242
+ { toggle: toggedItems[key] },
243
+ ]"
244
+ name="angle"
245
+ />
246
+ </button>
247
+ </div>
248
+ </div>
249
+ <slot
250
+ v-if="props.type"
251
+ :key="key"
252
+ name="type"
253
+ :item="item"
254
+ >
255
+ <div
256
+ :class="
257
+ item[0]?.disabled && 'clr-form-control-disabled'
258
+ "
259
+ >
260
+ <div
261
+ :class="`clr-${props.type}-wrapper flex-justify-center flex-align-center`"
262
+ >
263
+ <input
264
+ :id="`${props.testId}-${inputId}-${item[0].id}`"
265
+ :key="item[0].id"
266
+ v-model="selectedRowLocal"
267
+ :type="props.type"
268
+ :class="`${props.type}-btn`"
269
+ :value="item[0].id"
270
+ :disabled="item[0]?.disabled || false"
271
+ name="selected-store"
272
+ @change="
273
+ changeSelectedRow($event, item[0].id)
274
+ "
275
+ />
276
+ <label
277
+ :for="`${props.testId}-${inputId}-${item[0].id}`"
278
+ class="clr-control-label"
279
+ />
280
+ </div>
281
+ </div>
282
+ </slot>
283
+ </div>
284
+ <!--TODO refactoring (duplicate)-->
285
+ <div
286
+ v-if="$slots.toggleBlock && props.type"
287
+ class="datagrid-cell datagrid-fixed-width"
288
+ >
289
+ <div class="flex-align-center">
290
+ <button
291
+ :id="`${props.testId}-toggle-icon-${key}`"
292
+ class="datagrid-expandable-caret-button reset-btn"
293
+ @click="toggle(key)"
294
+ >
295
+ <atoms-the-icon
296
+ :class="[
297
+ 'datagrid-expandable-caret-icon',
298
+ { toggle: toggedItems[key] },
299
+ ]"
300
+ name="angle"
301
+ />
302
+ </button>
303
+ </div>
304
+ </div>
305
+ </div>
306
+ <div class="datagrid-row-scrollable">
307
+ <div class="datagrid-scrolling-cells">
308
+ <div
309
+ v-for="(item2, key2) in item"
310
+ v-show="
311
+ !isShowHiddenInfo ||
312
+ item2.key === 'col1' ||
313
+ item2.key === 'icon'
314
+ "
315
+ :key="key2"
316
+ :style="{
317
+ width: columnsWidth[key2][0],
318
+ minWidth: columnsWidth[key2][1],
319
+ }"
320
+ :class="[
321
+ 'datagrid-cell datagrid-fixed-width',
322
+ {
323
+ 'hidden-text-triangle':
324
+ isShowHiddenInfo &&
325
+ item2.data?.name === 'hidden-text-triangle',
326
+ },
327
+ ]"
328
+ >
329
+ <div
330
+ :class="[
331
+ 'flex-align-center h-100',
332
+ {
333
+ 'double-arrow-width':
334
+ item2.data?.name === 'doubleArrows',
335
+ },
336
+ ]"
337
+ >
338
+ <div
339
+ v-if="item2.data?.name === 'doubleArrows'"
340
+ :id="`show-info-${item[0].data.id}`"
341
+ :class="[
342
+ 'double-arrow-wrap',
343
+ {
344
+ 'arrow-selected':
345
+ isShowHiddenInfo &&
346
+ item2.id === selectedRow,
347
+ },
348
+ ]"
349
+ @click.prevent.stop="
350
+ doubleArrowClick(item2, item)
351
+ "
352
+ >
353
+ <atoms-the-icon
354
+ v-if="item2.data?.name === 'doubleArrows'"
355
+ name="doubleArrows"
356
+ :class="[
357
+ 'double-arrow',
358
+ {
359
+ 'arrow-selected':
360
+ isShowHiddenInfo &&
361
+ item2.id === selectedRow,
362
+ },
363
+ ]"
364
+ />
365
+ </div>
366
+ <span
367
+ v-if="item2.text && item2.data?.iconClassName"
368
+ class="vertical-divider"
369
+ />
370
+ <slot :name="item2.key" :item="item2">
371
+ <span class="text-ellipsis" :title="item2.text"
372
+ >{{ item2.text }}
373
+ </span>
374
+ </slot>
375
+ </div>
376
+ </div>
377
+ </div>
378
+ <div
379
+ v-show="toggedItems[key]"
380
+ class="datagrid-row-flex datagrid-row-detail datagrid-container"
381
+ >
382
+ <slot name="toggleBlock" :item="item" />
383
+ </div>
384
+ </div>
385
+ </div>
386
+ </div>
387
+ </div>
388
+ </template>
389
+ <template v-else>
390
+ <div class="datagrid-placeholder-container">
391
+ <div class="datagrid-placeholder datagrid-empty">
392
+ <div class="datagrid-placeholder-image"></div>
393
+
394
+ <span>No items found</span>
395
+ </div>
396
+ </div>
397
+ </template>
398
+ </div>
399
+ </div>
400
+ </div>
401
+
402
+ <div
403
+ v-if="!hideFooter"
404
+ :class="[
405
+ 'datagrid-footer',
406
+ {
407
+ 'datagrid-footer-opened-info': isShowHiddenInfo,
408
+ },
409
+ ]"
410
+ >
411
+ <div
412
+ v-if="props.type === 'checkbox' && props.selectedRow?.length"
413
+ class="clr-form-control-disabled"
414
+ >
415
+ <div class="clr-checkbox-wrapper">
416
+ <input
417
+ :id="`${props.testId}-check-all`"
418
+ type="checkbox"
419
+ checked
420
+ />
421
+ <label class="clr-control-label">
422
+ {{ props.selectedRow?.length }}
423
+ </label>
424
+ </div>
425
+ </div>
426
+ <div class="datagrid-footer-description flex-align-center">
427
+ <atoms-table-data-grid-column-switch
428
+ v-if="columnKeysLocal"
429
+ v-model:column-keys="columnKeysLocal"
430
+ :test-id="`${props.testId}-footer-description`"
431
+ class="switch-icon"
432
+ />
433
+
434
+ <div v-if="$slots.action" class="datagrid-footer__action">
435
+ <slot name="action" />
436
+ </div>
437
+ </div>
438
+
439
+ <atoms-table-data-grid-pagination
440
+ test-id="props.testId"
441
+ :page-size="props.pageSize"
442
+ :page="props.page"
443
+ :options="mergeOptions"
444
+ :total-items="props.totalItems"
445
+ :total-pages="props.totalPages"
446
+ :hide-pagination="props.hidePagination"
447
+ :hide-page-size="props.hidePageSize"
448
+ :show-page-info="props.showPageInfo"
449
+ :page-items-count="props.bodyItems.length"
450
+ :is-show-hidden-info="isShowHiddenInfo"
451
+ @change-page-size="changePageSize"
452
+ @change-page="changePage"
453
+ />
454
+ </div>
455
+
456
+ <atoms-loader v-show="props.loading" class="datagrid-spinner" />
457
+ </div>
458
+ </div>
459
+ <div
460
+ v-if="isShowInfo"
461
+ id="hidden-features"
462
+ :class="[
463
+ 'hidden-features',
464
+ {
465
+ 'show-hidden-info': isShowHiddenInfo,
466
+ },
467
+ ]"
468
+ >
469
+ <div class="header">
470
+ <slot name="hiddenInfoHeader" :item="showedInfoCol" />
471
+ <button
472
+ :id="`${props.testId}-hidden-info-toggle-icon-${showedInfoRow?.key}-${showedInfoRow?.data.name}`"
473
+ class="signpost-action close"
474
+ @click="isShowHiddenInfo = false"
475
+ >
476
+ <atoms-the-icon class="close-icon" name="close" />
477
+ </button>
478
+ </div>
479
+ <slot name="hiddenInfoBody" />
480
+ </div>
481
+ </div>
482
+ </template>
483
+
484
+ <script setup lang="ts">
485
+ import { UI_I_HTMLSelectElement } from '~/lib/models/interfaces'
486
+ import { itemsPerPage } from '~/components/atoms/table/dataGrid/lib/config/itemsPerPage'
487
+ import {
488
+ UI_I_HeadItem,
489
+ UI_I_BodyItem,
490
+ UI_I_ColumnKey,
491
+ } from '~/components/atoms/table/dataGrid/lib/models/interfaces'
492
+ import { UI_I_OptionItem } from '~/components/atoms/lib/models/interfaces'
493
+ import {
494
+ UI_T_ColumnKeys,
495
+ UI_T_DataGridType,
496
+ UI_T_SelectedRow,
497
+ } from '~/components/atoms/table/dataGrid/lib/models/types'
498
+
499
+ const props = withDefaults(
500
+ defineProps<{
501
+ headItems: UI_I_HeadItem[]
502
+ bodyItems: UI_I_BodyItem[][]
503
+ pageSize: number
504
+ page: number
505
+ totalItems: number
506
+ totalPages: number
507
+ loading?: boolean
508
+ columnKeys?: UI_I_ColumnKey[]
509
+ selectedRow?: UI_T_SelectedRow
510
+ type?: UI_T_DataGridType
511
+ itemsPerPage?: UI_I_OptionItem[]
512
+ offSelectByRow?: boolean
513
+ hidePageSize?: boolean
514
+ showPageInfo?: boolean
515
+ serverOff?: boolean
516
+ fillWidth?: boolean
517
+ hideFooter?: boolean
518
+ hidePagination?: boolean
519
+ testId?: string
520
+ withInfo?: boolean
521
+ rowAttributeIdName?: string
522
+ isMainFilter?: boolean
523
+ mainFilterPlaceholder?: string
524
+ }>(),
525
+ {
526
+ columnKeys: undefined,
527
+ selectedRow: undefined,
528
+ type: undefined,
529
+ itemsPerPage: undefined,
530
+ fillWidth: true,
531
+ testId: 'ui-data-grid',
532
+ withInfo: false,
533
+ rowAttributeIdName: 'data-id',
534
+ }
535
+ )
536
+
537
+ const emits = defineEmits<{
538
+ (event: 'update:column-keys', value: UI_T_ColumnKeys): void
539
+ (event: 'update:selected-row', value: UI_T_SelectedRow): void
540
+ (event: 'update:page-size', value: number): void
541
+ (event: 'update:page', value: number): void
542
+ (event: 'main-filter', value: string): void
543
+ (event: 'filtering', value: string[][]): void
544
+ (event: 'sorting', value: [string, boolean]): void
545
+ (event: 'change', value: any): void
546
+ (event: 'row-detail', value: number): void
547
+ }>()
548
+
549
+ const mainFilter = ref<string>('')
550
+
551
+ const mergeOptions = computed<UI_I_OptionItem[]>(
552
+ () => props.itemsPerPage || itemsPerPage
553
+ )
554
+
555
+ const inputId = ref<string>(`radio-input-${useUniqueId()}`)
556
+
557
+ const columnKeysLocal = computed<UI_T_ColumnKeys>({
558
+ get() {
559
+ return props.columnKeys
560
+ },
561
+ set(newValue) {
562
+ emits('update:column-keys', newValue)
563
+ },
564
+ })
565
+
566
+ const selectedAll = ref<boolean>(false)
567
+ const changeAll = (e: UI_I_HTMLSelectElement): void => {
568
+ const newSelectedRow: (number | string)[] = []
569
+ if (e.target.checked) {
570
+ bodyItemsPresent.value.forEach((row) => {
571
+ if (row[0]?.disabled) return
572
+
573
+ newSelectedRow.push(row[0].id)
574
+ })
575
+ }
576
+
577
+ emits('update:selected-row', newSelectedRow)
578
+ }
579
+
580
+ const selectedRowLocal = ref<UI_T_SelectedRow>([])
581
+ const isShowHiddenInfo = ref<boolean>(false)
582
+ const tableWrapperId = `table-wrapper-${useUniqueId()}`
583
+ let memoryWidth = '0'
584
+
585
+ const showedInfoRow = ref<UI_I_BodyItem | null>(null)
586
+ const showedInfoCol = ref<UI_I_BodyItem[] | null>(null)
587
+
588
+ const isShowInfo = computed(
589
+ () =>
590
+ showedInfoRow.value &&
591
+ showedInfoRow.value.id === props.selectedRow &&
592
+ !showedInfoRow.value.data?.text &&
593
+ isShowHiddenInfo.value
594
+ )
595
+
596
+ const setShowedInfoData = (
597
+ item: UI_I_BodyItem | null,
598
+ items: UI_I_BodyItem[] | null,
599
+ reset: boolean = false
600
+ ): void => {
601
+ showedInfoRow.value = item
602
+ showedInfoCol.value = items
603
+
604
+ reset && (isShowHiddenInfo.value = false)
605
+ item && selectRowById(item)
606
+ reset && (isShowHiddenInfo.value = true)
607
+ }
608
+
609
+ const doubleArrowClick = (
610
+ item: UI_I_BodyItem,
611
+ items: UI_I_BodyItem[]
612
+ ): void => {
613
+ if (!isShowHiddenInfo.value) {
614
+ setShowedInfoData(item, items)
615
+ } else {
616
+ if (showedInfoRow.value?.id !== item.id) {
617
+ setShowedInfoData(item, items, true)
618
+
619
+ return
620
+ } else {
621
+ setShowedInfoData(null, null)
622
+ }
623
+ }
624
+
625
+ isShowHiddenInfo.value = !isShowHiddenInfo.value
626
+ }
627
+
628
+ watch(
629
+ () => props.selectedRow,
630
+ (newValue) => {
631
+ if (newValue === undefined) return
632
+
633
+ if (Array.isArray(newValue) && !newValue.length) selectedAll.value = false
634
+
635
+ selectedRowLocal.value = newValue
636
+ },
637
+ { immediate: true }
638
+ )
639
+ const selectRowById = (item: UI_I_BodyItem): void => {
640
+ const { id, disabled } = item
641
+
642
+ if (props.offSelectByRow || isShowHiddenInfo.value || disabled) return
643
+
644
+ if (props.type === 'checkbox' && Array.isArray(selectedRowLocal.value)) {
645
+ const has = selectedRowLocal.value.includes(id)
646
+ if (has) {
647
+ selectedRowLocal.value = selectedRowLocal.value.filter(
648
+ (rowId: string | number) => rowId !== id
649
+ )
650
+ } else {
651
+ selectedRowLocal.value.push(id)
652
+ }
653
+
654
+ emits('change', selectedRowLocal.value)
655
+ emits('update:selected-row', selectedRowLocal.value)
656
+
657
+ changeSelectedAll(!has)
658
+ return
659
+ }
660
+
661
+ emits('change', id)
662
+ emits('update:selected-row', id)
663
+ }
664
+ const changeSelectedRow = (
665
+ e: UI_I_HTMLSelectElement,
666
+ id: number | string
667
+ ): void => {
668
+ if (props.type === 'checkbox' && Array.isArray(selectedRowLocal.value)) {
669
+ const newSelectedRow = [...selectedRowLocal.value]
670
+ emits('change', newSelectedRow)
671
+ emits('update:selected-row', newSelectedRow)
672
+
673
+ changeSelectedAll(e.target.checked)
674
+ return
675
+ }
676
+
677
+ emits('change', id)
678
+ emits('update:selected-row', id)
679
+ }
680
+ const changeSelectedAll = (checked: boolean): void => {
681
+ if (props.type === 'checkbox' && Array.isArray(selectedRowLocal.value)) {
682
+ const newSelectedRow = [...selectedRowLocal.value]
683
+
684
+ if (!checked) {
685
+ selectedAll.value = false
686
+ } else if (newSelectedRow.length === bodyItemsPresent.value.length) {
687
+ selectedAll.value = true
688
+ }
689
+ }
690
+ }
691
+
692
+ const checkIsSelectedRow = (id: number | string): boolean => {
693
+ if (props.type === 'checkbox' && Array.isArray(props.selectedRow)) {
694
+ return props.selectedRow.includes(id)
695
+ }
696
+ return props.selectedRow === id
697
+ }
698
+
699
+ // Sorting
700
+ const sortInfo = ref<[string, boolean]>(['', true])
701
+ const sortedColumnIndex = computed<number>(() => {
702
+ let index = -1
703
+ headItemsPresent.value.forEach((item, key) => {
704
+ if (item.sortColumn === sortInfo.value[0]) index = key
705
+ })
706
+
707
+ return index
708
+ })
709
+ const sortTable = (sortName: string): void => {
710
+ if (!sortName) return
711
+
712
+ emits('update:selected-row', selectedRowLocal.value)
713
+
714
+ if (sortInfo.value[0] === sortName) {
715
+ sortInfo.value[1] = !sortInfo.value[1]
716
+
717
+ emits('sorting', sortInfo.value)
718
+ return
719
+ }
720
+ sortInfo.value[0] = sortName
721
+ sortInfo.value[1] = true
722
+
723
+ emits('sorting', sortInfo.value)
724
+ }
725
+
726
+ // Filtering
727
+ const filterShow = ref<boolean[]>([])
728
+ const filterTerm = ref<string[]>([])
729
+ const filtering = (): void => {
730
+ const filter: string[][] = []
731
+ headItemsPresent.value.forEach((item, key) => {
732
+ if (filterTerm.value[key]) filter.push([item.key, filterTerm.value[key]])
733
+ })
734
+
735
+ emits('filtering', filter)
736
+ }
737
+
738
+ // Pagination
739
+ const changePageSize = (value: number): void => {
740
+ emits('update:page-size', value)
741
+ }
742
+ const changePage = (value: number): void => {
743
+ emits('update:page', value)
744
+ }
745
+
746
+ const headItemsPresent = computed<UI_I_HeadItem[]>(() => {
747
+ if (!columnKeysLocal.value) {
748
+ return props.headItems
749
+ }
750
+
751
+ return props.headItems.filter((item, key) => {
752
+ return columnKeysLocal.value?.find(
753
+ (item2, key2) => item2.key === item.key && key === key2
754
+ )?.show
755
+ })
756
+ })
757
+
758
+ const bodyItemsPresent = computed<UI_I_BodyItem[][]>(() => {
759
+ let items: UI_I_BodyItem[][] = props.bodyItems
760
+
761
+ // Filtering by column
762
+ if (columnKeysLocal.value) {
763
+ items = items.map((arr) => {
764
+ arr = arr.filter((item, key) => {
765
+ return columnKeysLocal.value?.find(
766
+ (item2, key2) => item2.key === item.key && key === key2
767
+ )?.show
768
+ })
769
+ return arr
770
+ })
771
+ }
772
+
773
+ if (props.serverOff) {
774
+ // Sorting
775
+ if (sortInfo.value[0] !== '') {
776
+ items = useDeepCopy(items).sort(
777
+ (a: UI_I_BodyItem[], b: UI_I_BodyItem[]) => {
778
+ let first = a[sortedColumnIndex.value].text.toString().toLowerCase()
779
+ let second = b[sortedColumnIndex.value].text.toString().toLowerCase()
780
+
781
+ const sortValueA = a[sortedColumnIndex.value]?.data?.sortValue
782
+ const sortValueB = b[sortedColumnIndex.value]?.data?.sortValue
783
+ if (sortValueA || sortValueA === 0) {
784
+ first = sortValueA
785
+ }
786
+ if (sortValueB || sortValueB === 0) {
787
+ second = sortValueB
788
+ }
789
+
790
+ if (sortInfo.value[1]) {
791
+ return first > second ? 1 : first < second ? -1 : 0
792
+ } else {
793
+ return first < second ? 1 : first > second ? -1 : 0
794
+ }
795
+ }
796
+ )
797
+ }
798
+ // Filtering
799
+ const hasFilter = headItemsPresent.value.some(
800
+ (_, key) => filterTerm.value[key]
801
+ )
802
+ if (hasFilter) {
803
+ items = items.filter((row) => {
804
+ // 0 - начальное значение
805
+ // 1 - найден элемент
806
+ // -1 - ненайден элемент
807
+ let hasItem = 0
808
+ headItemsPresent.value.forEach((item, key) => {
809
+ if (!filterTerm.value[key]) return
810
+ const term = filterTerm.value[key].toLowerCase()
811
+
812
+ row.forEach((col) => {
813
+ if (
814
+ col.key === item.key &&
815
+ typeof col.text === 'string' &&
816
+ hasItem != -1
817
+ ) {
818
+ hasItem = col.text.toLowerCase().includes(term) ? 1 : -1
819
+ }
820
+ })
821
+ })
822
+
823
+ return hasItem === 1
824
+ })
825
+ }
826
+ }
827
+
828
+ return items
829
+ })
830
+
831
+ const toggedItems = ref<boolean[]>([])
832
+
833
+ const toggle = (key: number): void => {
834
+ toggedItems.value[key] = !toggedItems.value[key]
835
+ if (!toggedItems.value[key]) return
836
+ emits('row-detail', key)
837
+ }
838
+
839
+ const outerWrapper = `datagrid-outer-wrapper${useUniqueId()}`
840
+ const expandableCaret = `datagrid-expandable-caret${useUniqueId()}`
841
+
842
+ // Resize
843
+ let helper = false
844
+ let setColumnWidth = (): void => {
845
+ if (!helper) {
846
+ columnsWidth.value = []
847
+ headItemsPresent.value.forEach((item) => {
848
+ columnsWidth.value.push([
849
+ item.width, // width
850
+ item.width, // min-width
851
+ ])
852
+ })
853
+
854
+ helper = true
855
+ setTimeout(() => setColumnWidth(), 0)
856
+ return
857
+ }
858
+ // Не продолжаем, чтобы ширина калонок была так как заданно в headItemsPresent
859
+ if (!props.fillWidth) return
860
+
861
+ const dataGridWidth = document.getElementById(outerWrapper)?.clientWidth || 0
862
+ const leftColumnWidth =
863
+ document.getElementById(expandableCaret)?.clientWidth || 0
864
+ const bordersWidth = 2
865
+ const columnWidth =
866
+ (dataGridWidth - leftColumnWidth - bordersWidth) /
867
+ headItemsPresent.value.length
868
+
869
+ headItemsPresent.value.forEach((item) => {
870
+ columnsWidth.value.push([
871
+ `${columnWidth}px`, // width
872
+ item.width, // min-width
873
+ ])
874
+ })
875
+ }
876
+ setColumnWidth = useThrottle(setColumnWidth)
877
+
878
+ const columnsWidth = ref<[string, string][]>([])
879
+ watch(
880
+ bodyItemsPresent,
881
+ (newValue: UI_I_BodyItem[][]) => {
882
+ newValue.forEach(() => {
883
+ toggedItems.value.push(false)
884
+ })
885
+ setColumnWidth()
886
+ },
887
+ {
888
+ immediate: true,
889
+ deep: true,
890
+ }
891
+ )
892
+
893
+ watch(
894
+ headItemsPresent,
895
+ (newValue: UI_I_HeadItem[]) => {
896
+ filterShow.value = newValue.map(() => false)
897
+ filterTerm.value = newValue.map(() => '')
898
+ },
899
+ {
900
+ immediate: true,
901
+ deep: true,
902
+ }
903
+ )
904
+
905
+ const grabColumn = ref<number>(-1)
906
+ const grabStartX = ref<number>(0)
907
+ const setGrab = (key: number, e: MouseEvent): void => {
908
+ if (props.withInfo && key === 0) return
909
+
910
+ if (!isShowHiddenInfo.value) {
911
+ grabColumn.value = key
912
+ const currentWidth = parseInt(columnsWidth.value[grabColumn.value][0])
913
+ grabStartX.value = e.clientX - currentWidth
914
+ }
915
+ }
916
+
917
+ const isDrag = ref<boolean>(false)
918
+
919
+ const mouseup = (): void => {
920
+ if (grabColumn.value === -1) {
921
+ return
922
+ }
923
+
924
+ grabColumn.value = -1
925
+ isDrag.value = false
926
+ }
927
+
928
+ let resizeObserve: ResizeObserver
929
+ let mousemove = (e: MouseEvent): void => {
930
+ if (grabColumn.value === -1) return
931
+
932
+ e.preventDefault()
933
+ isDrag.value = true
934
+ resizeObserve.disconnect()
935
+
936
+ const minWidth = parseInt(columnsWidth.value[grabColumn.value][1])
937
+ const changeX = Math.max(e.clientX - grabStartX.value, minWidth)
938
+
939
+ columnsWidth.value[grabColumn.value] = [`${changeX}px`, `${minWidth}px`]
940
+ }
941
+ mousemove = useThrottle(mousemove)
942
+
943
+ const setResizeObserve = (): void => {
944
+ const el = document.getElementById(outerWrapper)
945
+
946
+ if (!el) {
947
+ setTimeout(setResizeObserve, 0)
948
+ return
949
+ }
950
+
951
+ resizeObserve = new ResizeObserver(setColumnWidth)
952
+ resizeObserve.observe(el)
953
+ }
954
+
955
+ let resizeObserveWithInfo: ResizeObserver
956
+
957
+ const setColumnWidthWithInfo = (ent: ResizeObserverEntry[]): void => {
958
+ if (isShowHiddenInfo.value) {
959
+ memoryWidth = columnsWidth.value[1][0]
960
+ columnsWidth.value[1][0] = `${ent[0].contentBoxSize[0].inlineSize - 86}px`
961
+ } else {
962
+ columnsWidth.value[1][0] = memoryWidth
963
+ }
964
+ }
965
+
966
+ const setResizeObserveWithInfo = (): void => {
967
+ const el = document.querySelector('.datagrid')
968
+
969
+ if (!el) {
970
+ setTimeout(setResizeObserveWithInfo, 0)
971
+ return
972
+ }
973
+
974
+ resizeObserveWithInfo = new ResizeObserver(setColumnWidthWithInfo)
975
+ resizeObserveWithInfo.observe(el)
976
+ }
977
+
978
+ onMounted(() => {
979
+ window.addEventListener('mousemove', mousemove)
980
+ window.addEventListener('mouseup', mouseup)
981
+
982
+ if (props.withInfo) {
983
+ setResizeObserveWithInfo()
984
+ }
985
+
986
+ setResizeObserve()
987
+ })
988
+ onUnmounted(() => {
989
+ window.removeEventListener('mouseup', mouseup)
990
+ window.removeEventListener('mousemove', mousemove)
991
+ })
992
+ </script>
993
+
994
+ <style scoped lang="scss">
995
+ @import '~/assets/scss/common/mixins';
996
+ .datagrid-outer-wrapper {
997
+ @include flex($dir: row);
998
+ padding-top: 12px;
999
+ flex-grow: 1;
1000
+ overflow: auto;
1001
+
1002
+ &.datagrid-outer-wrapper-opened-info {
1003
+ width: 35%;
1004
+ min-width: 195px;
1005
+ }
1006
+
1007
+ & * {
1008
+ box-sizing: border-box;
1009
+ }
1010
+
1011
+ & svg {
1012
+ fill: var(--table-color);
1013
+ }
1014
+
1015
+ .datagrid-inner-wrapper {
1016
+ @include flex($dir: column);
1017
+ flex-grow: 1;
1018
+ overflow: auto;
1019
+
1020
+ .main-filter-content {
1021
+ align-items: center;
1022
+
1023
+ .filter-icon {
1024
+ width: 16px;
1025
+ height: 16px;
1026
+ margin-right: 10px;
1027
+ }
1028
+ }
1029
+ .datagrid {
1030
+ overflow: auto;
1031
+ flex: 1 1 auto;
1032
+ border-radius: 0.125rem 0.125rem 0 0;
1033
+ background-color: var(--block-view-bg-color);
1034
+ border-color: var(--global-border-color);
1035
+
1036
+ &.datagrid-opened-info {
1037
+ border-radius: 0.125rem 0 0 0;
1038
+ overflow-x: hidden;
1039
+ }
1040
+
1041
+ .datagrid-table-wrapper {
1042
+ min-width: max-content;
1043
+ display: flex;
1044
+ flex: 1 1 auto;
1045
+ min-height: 100%;
1046
+
1047
+ .datagrid-table {
1048
+ @include flex($dir: column);
1049
+ flex: 1 1 auto;
1050
+ align-content: flex-start;
1051
+ position: relative;
1052
+
1053
+ .datagrid-header {
1054
+ position: sticky;
1055
+ top: 0;
1056
+ z-index: 501;
1057
+ width: auto;
1058
+
1059
+ .datagrid-row-scrollable {
1060
+ flex-direction: row;
1061
+
1062
+ .datagrid-column-separator {
1063
+ user-select: none;
1064
+
1065
+ &::after {
1066
+ cursor: col-resize;
1067
+ }
1068
+ &.double-arrow-separator .datagrid-column-handle {
1069
+ cursor: unset;
1070
+ }
1071
+ &.double-arrow-separator::after {
1072
+ cursor: unset;
1073
+ }
1074
+ }
1075
+ }
1076
+
1077
+ .datagrid-row {
1078
+ color: var(--table-color);
1079
+ background-color: var(--block-view-bg-color);
1080
+
1081
+ &.datagrid-selected {
1082
+ background-color: var(--row-selected-bg-color);
1083
+ border-bottom: 1px solid var(--global-border-color);
1084
+
1085
+ & :deep(*) {
1086
+ color: var(--table-active-color);
1087
+ }
1088
+ }
1089
+
1090
+ .datagrid-column {
1091
+ background-color: var(--block-view-bg-color);
1092
+ border-bottom: 1px solid var(--global-border-color);
1093
+ padding: 6px 12px 5px;
1094
+ position: relative;
1095
+ //flex: 1 1 auto;
1096
+
1097
+ &:last-child {
1098
+ flex: 1 1 auto;
1099
+ }
1100
+
1101
+ &.datagrid-toggle-block {
1102
+ width: 38px;
1103
+ min-width: 38px;
1104
+
1105
+ .datagrid-column-separator {
1106
+ cursor: default;
1107
+
1108
+ &::after {
1109
+ cursor: default;
1110
+ }
1111
+ }
1112
+ }
1113
+ }
1114
+
1115
+ .datagrid-column-title {
1116
+ align-self: auto;
1117
+ color: var(--table-color);
1118
+ background-color: var(--block-view-bg-color);
1119
+ border-bottom-color: var(--global-border-color);
1120
+ font-size: 11px;
1121
+ @include flex($align: center);
1122
+ display: flex;
1123
+ flex-direction: row;
1124
+ justify-content: flex-start;
1125
+ align-items: center;
1126
+ //line-height: 24px;
1127
+ line-height: normal;
1128
+
1129
+ .title-column {
1130
+ font-weight: bold;
1131
+ font-size: 11px;
1132
+ overflow: hidden;
1133
+ text-wrap: none;
1134
+ text-overflow: ellipsis;
1135
+ }
1136
+
1137
+ .sort-arrow-wrap {
1138
+ margin-left: auto;
1139
+ height: 14px;
1140
+ width: 14px;
1141
+ min-height: 14px;
1142
+ min-width: 14px;
1143
+ vertical-align: middle;
1144
+
1145
+ .sort-arrow {
1146
+ &.down {
1147
+ transform: rotate(180deg);
1148
+ }
1149
+ }
1150
+ }
1151
+ .title-icon {
1152
+ width: 24px;
1153
+ height: 24px;
1154
+ }
1155
+ }
1156
+
1157
+ .datagrid-filter-toggle {
1158
+ background: unset;
1159
+ margin-top: -4px;
1160
+ align-self: center;
1161
+
1162
+ .filter-icon {
1163
+ width: 16px;
1164
+ height: 16px;
1165
+ }
1166
+ }
1167
+ }
1168
+ }
1169
+
1170
+ .datagrid-placeholder-container {
1171
+ .datagrid-placeholder.datagrid-empty {
1172
+ background: var(--block-view-bg-color);
1173
+ }
1174
+ span {
1175
+ font-size: 16px;
1176
+ color: var(--global-font-color4);
1177
+ }
1178
+ }
1179
+
1180
+ .datagrid-row {
1181
+ width: 100%;
1182
+ min-width: max-content;
1183
+ border-top: none;
1184
+ color: var(--table-color);
1185
+ background-color: var(--block-view-bg-color);
1186
+ border-bottom: 1px solid var(--global-border-color);
1187
+
1188
+ &.datagrid-selected {
1189
+ & :deep(*) {
1190
+ color: var(--table-active-color);
1191
+ }
1192
+
1193
+ .datagrid-cell {
1194
+ background-color: var(--row-selected-bg-color);
1195
+ border-bottom: 1px solid var(--global-border-color);
1196
+ position: relative;
1197
+ line-height: 1rem;
1198
+ }
1199
+
1200
+ .datagrid-row-detail {
1201
+ background-color: var(--row-selected-bg-color);
1202
+ border-bottom: 1px solid var(--global-border-color);
1203
+ }
1204
+ }
1205
+
1206
+ .datagrid-cell {
1207
+ min-width: 38px;
1208
+ min-height: 28px;
1209
+ padding: 2px 12px 3px 12px;
1210
+ position: relative;
1211
+
1212
+ &:has(.double-arrow-wrap) {
1213
+ padding-left: 4px;
1214
+ }
1215
+
1216
+ &:has(.double-arrow-wrap)::after {
1217
+ content: '';
1218
+ width: 0.5px;
1219
+ height: calc(100% - 6px);
1220
+ position: absolute;
1221
+ right: 2px;
1222
+ top: 3px;
1223
+ background-color: var(--global-border-color);
1224
+ }
1225
+
1226
+ &:last-child {
1227
+ flex: 1 1 auto;
1228
+ }
1229
+
1230
+ button {
1231
+ height: 0.9rem;
1232
+ width: 0.9rem;
1233
+
1234
+ .arrow-icon {
1235
+ width: 16px;
1236
+ height: 16px;
1237
+ transform: rotate(90deg);
1238
+ }
1239
+ }
1240
+
1241
+ .datagrid-cell-icon {
1242
+ display: inline-block;
1243
+ width: 16px;
1244
+ height: 16px;
1245
+ }
1246
+
1247
+ .datagrid-expandable-caret-button {
1248
+ cursor: pointer;
1249
+ width: 100%;
1250
+
1251
+ .datagrid-expandable-caret-icon {
1252
+ width: 16px;
1253
+ height: 16px;
1254
+ transform: rotate(90deg);
1255
+ fill: var(--table-caret-color);
1256
+
1257
+ &.toggle {
1258
+ transform: rotate(180deg);
1259
+ }
1260
+ }
1261
+ }
1262
+ }
1263
+
1264
+ &.datagrid-selected-info {
1265
+ width: 100%;
1266
+ min-width: max-content;
1267
+ border-top: none;
1268
+ color: var(--table-color);
1269
+ background-color: var(--block-view-bg-color);
1270
+
1271
+ .datagrid-cell {
1272
+ position: relative;
1273
+
1274
+ &.hidden-text-triangle::after {
1275
+ content: '';
1276
+ position: absolute;
1277
+ transform: rotate(225deg);
1278
+ border-bottom: 15px solid transparent;
1279
+ border-right: 15px solid var(--global-bg-color);
1280
+ bottom: 26%;
1281
+ right: -16px;
1282
+ z-index: 1000;
1283
+ }
1284
+
1285
+ &.hidden-text-triangle::before {
1286
+ content: '';
1287
+ transform: rotate(-135deg);
1288
+ position: absolute;
1289
+ border-bottom: 16px solid transparent;
1290
+ border-right: 16px solid var(--global-border-color);
1291
+ bottom: 23%;
1292
+ right: -17px;
1293
+ z-index: 999;
1294
+ }
1295
+ }
1296
+ }
1297
+ }
1298
+
1299
+ .datagrid-row-sticky {
1300
+ @include flex($w: nowrap);
1301
+ position: sticky;
1302
+ left: 0;
1303
+ z-index: 500;
1304
+ background-color: var(--block-view-bg-color);
1305
+
1306
+ .datagrid-column {
1307
+ color: var(--table-color);
1308
+ background-color: var(--block-view-bg-color);
1309
+ border-bottom-color: var(--global-border-color);
1310
+ text-align: left;
1311
+ display: flex;
1312
+ flex: 1 1 auto;
1313
+ vertical-align: top;
1314
+ border: none;
1315
+
1316
+ &.datagrid-expandable-caret {
1317
+ .datagrid-column-separator {
1318
+ display: block;
1319
+
1320
+ &::after {
1321
+ top: 0;
1322
+ height: 18px;
1323
+ }
1324
+ }
1325
+
1326
+ .radio-btn {
1327
+ width: 16px;
1328
+ height: 16px;
1329
+ }
1330
+ }
1331
+
1332
+ .datagrid-column-separator {
1333
+ position: relative;
1334
+ //left: 0.6rem;
1335
+ flex: 0 0 auto;
1336
+ width: 0.05rem;
1337
+ order: 100;
1338
+ margin-left: auto;
1339
+ height: 100%;
1340
+ }
1341
+ }
1342
+
1343
+ .datagrid-fixed-column-without-separator {
1344
+ background-color: var(--block-view-bg-color);
1345
+
1346
+ &::after {
1347
+ background-color: transparent;
1348
+ }
1349
+ }
1350
+
1351
+ .datagrid-fixed-column {
1352
+ background-color: var(--block-view-bg-color);
1353
+
1354
+ &::after {
1355
+ content: '';
1356
+ width: 0.05rem;
1357
+ height: calc(100% - 0.5rem);
1358
+ position: absolute;
1359
+ right: 0;
1360
+ top: 0.25rem;
1361
+ background-color: var(--global-border-color);
1362
+ }
1363
+
1364
+ .clr-form-control-disabled {
1365
+ .clr-checkbox-wrapper {
1366
+ label {
1367
+ cursor: not-allowed;
1368
+ }
1369
+ }
1370
+ }
1371
+ }
1372
+ }
1373
+
1374
+ .datagrid-row-scrollable {
1375
+ @include flex($ff: row nowrap);
1376
+ flex: 1 1 auto;
1377
+
1378
+ .datagrid-scrolling-cells {
1379
+ @include flex($ff: row nowrap);
1380
+ flex: 1 1 auto;
1381
+ }
1382
+ }
1383
+ .datagrid-body-row {
1384
+ .datagrid-row-scrollable {
1385
+ @include flex($ff: column nowrap);
1386
+
1387
+ .datagrid-row-detail {
1388
+ flex: 1;
1389
+ }
1390
+ }
1391
+
1392
+ &:not(.datagrid-selected):hover {
1393
+ border-bottom: 1px solid var(--table-hover-row-border-color);
1394
+ background-color: var(--table-hover-row-background-color);
1395
+ color: var(--table-hover-row-color);
1396
+
1397
+ .datagrid-fixed-column {
1398
+ background-color: var(--table-hover-row-background-color);
1399
+ }
1400
+ .datagrid-cell {
1401
+ background-color: var(--table-hover-row-background-color);
1402
+ }
1403
+ }
1404
+ }
1405
+ }
1406
+ }
1407
+ }
1408
+
1409
+ .datagrid-footer {
1410
+ flex: 0 0 auto;
1411
+ @include flex($ff: row nowrap, $just: space-between, $align: stretch);
1412
+ font-size: 0.55rem;
1413
+ background-color: var(--block-view-bg-color);
1414
+ border: 0.05rem solid var(--global-border-color);
1415
+ border-top: none;
1416
+ border-radius: 0 0 0.15rem 0.15rem;
1417
+ padding: 0 0.6rem;
1418
+ height: 28px;
1419
+
1420
+ &.datagrid-footer-opened-info {
1421
+ border-radius: 0 0 0 0.15rem;
1422
+ flex-direction: row-reverse;
1423
+ }
1424
+
1425
+ .clr-form-control-disabled {
1426
+ opacity: 1;
1427
+
1428
+ .clr-checkbox-wrapper {
1429
+ label {
1430
+ color: #8c8c8c;
1431
+ margin-right: 9px;
1432
+ padding-left: 22px;
1433
+ &:before {
1434
+ position: absolute;
1435
+ top: 4px;
1436
+ left: 0;
1437
+ content: '';
1438
+ display: inline-block;
1439
+ height: 16px;
1440
+ width: 16px;
1441
+ border: none;
1442
+ border-radius: 3px;
1443
+ background-color: var(--table-checkbox-color);
1444
+ }
1445
+
1446
+ &:after {
1447
+ position: absolute;
1448
+ content: '';
1449
+ display: inline-block;
1450
+ height: 5px;
1451
+ width: 8px;
1452
+ border-left: 2px solid #fff;
1453
+ border-bottom: 2px solid #fff;
1454
+ top: 4px;
1455
+ left: 4px;
1456
+ transform: translateY(4px) rotate(-45deg);
1457
+ }
1458
+ }
1459
+ }
1460
+ }
1461
+ }
1462
+
1463
+ .datagrid-spinner {
1464
+ top: 0.6rem;
1465
+ height: calc(100% - 0.6rem);
1466
+ }
1467
+
1468
+ .datagrid-footer-description {
1469
+ flex: 1 1 auto;
1470
+
1471
+ :deep(svg) {
1472
+ fill: var(--table-switch-color);
1473
+ }
1474
+ }
1475
+
1476
+ .clr-radio-wrapper,
1477
+ .clr-checkbox-wrapper {
1478
+ height: 18px;
1479
+ }
1480
+
1481
+ .clr-radio-wrapper label,
1482
+ .clr-checkbox-wrapper label {
1483
+ padding-left: 16px;
1484
+ }
1485
+ }
1486
+ }
1487
+ //.vertical-divider {
1488
+ // width: 1px;
1489
+ // height: 22px;
1490
+ // background: #bbb;
1491
+ // margin: 2px 2px 0 -5px;
1492
+ //}
1493
+
1494
+ .hidden-features {
1495
+ padding: 9px 14px;
1496
+ background-color: var(--global-bg-color);
1497
+ color: var(--global-font-color2);
1498
+ border: 1px solid var(--global-border-color);
1499
+ border-left: none;
1500
+ overflow-y: auto;
1501
+ overflow-x: hidden;
1502
+ width: 65%;
1503
+
1504
+ .header {
1505
+ display: flex;
1506
+ align-items: center;
1507
+ justify-content: space-between;
1508
+ background-color: inherit;
1509
+
1510
+ h3 {
1511
+ font-size: 1rem;
1512
+ color: var(--global-font-color2) !important;
1513
+ line-height: 1.7rem;
1514
+ }
1515
+ button {
1516
+ line-height: 24px;
1517
+
1518
+ .close-icon {
1519
+ margin-left: 10px;
1520
+ width: 24px;
1521
+ height: 24px;
1522
+ }
1523
+ }
1524
+ }
1525
+ }
1526
+ .double-arrow-width {
1527
+ width: 25px;
1528
+ }
1529
+ .double-arrow-wrap {
1530
+ width: 30px;
1531
+ height: 20px;
1532
+ padding-top: 1px;
1533
+ padding-left: 5px;
1534
+ cursor: pointer;
1535
+ background-color: transparent;
1536
+
1537
+ .double-arrow {
1538
+ background-color: transparent;
1539
+ transform: rotate(90deg);
1540
+ width: 16px;
1541
+ height: 16px;
1542
+ }
1543
+
1544
+ .double-arrow.arrow-selected {
1545
+ transform: rotate(-90deg) !important;
1546
+ background-color: #0079b8;
1547
+ }
1548
+ }
1549
+ .double-arrow-wrap.arrow-selected {
1550
+ background-color: #0079b8;
1551
+ border-radius: 3px;
1552
+ }
1553
+ </style>
1554
+
1555
+ <style>
1556
+ :root {
1557
+ --table-color: #565656;
1558
+ --table-active-color: #fff;
1559
+ --table-checkbox-color: #454545;
1560
+ --table-caret-color: #454545;
1561
+ --table-switch-color: #575757;
1562
+ --table-hover-row-border-color: #666;
1563
+ --table-hover-row-background-color: #e8e8e8;
1564
+ --table-hover-row-color: #454545;
1565
+ --table-spinner-bg-color: #ffffff99;
1566
+ }
1567
+
1568
+ :root.dark-theme {
1569
+ --table-color: #fff;
1570
+ --table-active-color: #565656;
1571
+ --table-checkbox-color: #49aeda;
1572
+ --table-caret-color: #ffffff;
1573
+ --table-switch-color: #b3b3b3;
1574
+ --table-hover-row-border-color: #fff;
1575
+ --table-hover-row-background-color: #324f61;
1576
+ --table-hover-row-color: #e9ecef;
1577
+ --table-spinner-bg-color: rgba(0, 0, 0, 0.5);
1578
+ }
1579
+ </style>