bfg-common 1.3.93 → 1.3.95

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,1569 +1,1576 @@
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
- const first = a[sortedColumnIndex.value].text.toString().toLowerCase()
776
- const second = b[sortedColumnIndex.value].text
777
- .toString()
778
- .toLowerCase()
779
-
780
- if (sortInfo.value[1]) {
781
- return first > second ? 1 : first < second ? -1 : 0
782
- } else {
783
- return first < second ? 1 : first > second ? -1 : 0
784
- }
785
- }
786
- )
787
- }
788
- // Filtering
789
- const hasFilter = headItemsPresent.value.some(
790
- (_, key) => filterTerm.value[key]
791
- )
792
- if (hasFilter) {
793
- items = items.filter((row) => {
794
- // 0 - начальное значение
795
- // 1 - найден элемент
796
- // -1 - ненайден элемент
797
- let hasItem = 0
798
- headItemsPresent.value.forEach((item, key) => {
799
- if (!filterTerm.value[key]) return
800
- const term = filterTerm.value[key].toLowerCase()
801
-
802
- row.forEach((col) => {
803
- if (
804
- col.key === item.key &&
805
- typeof col.text === 'string' &&
806
- hasItem != -1
807
- ) {
808
- hasItem = col.text.toLowerCase().includes(term) ? 1 : -1
809
- }
810
- })
811
- })
812
-
813
- return hasItem === 1
814
- })
815
- }
816
- }
817
-
818
- return items
819
- })
820
-
821
- const toggedItems = ref<boolean[]>([])
822
-
823
- const toggle = (key: number): void => {
824
- toggedItems.value[key] = !toggedItems.value[key]
825
- if (!toggedItems.value[key]) return
826
- emits('row-detail', key)
827
- }
828
-
829
- const outerWrapper = `datagrid-outer-wrapper${useUniqueId()}`
830
- const expandableCaret = `datagrid-expandable-caret${useUniqueId()}`
831
-
832
- // Resize
833
- let helper = false
834
- let setColumnWidth = (): void => {
835
- if (!helper) {
836
- columnsWidth.value = []
837
- headItemsPresent.value.forEach((item) => {
838
- columnsWidth.value.push([
839
- item.width, // width
840
- item.width, // min-width
841
- ])
842
- })
843
-
844
- helper = true
845
- setTimeout(() => setColumnWidth(), 0)
846
- return
847
- }
848
- // Не продолжаем, чтобы ширина калонок была так как заданно в headItemsPresent
849
- if (!props.fillWidth) return
850
-
851
- const dataGridWidth = document.getElementById(outerWrapper)?.clientWidth || 0
852
- const leftColumnWidth =
853
- document.getElementById(expandableCaret)?.clientWidth || 0
854
- const bordersWidth = 2
855
- const columnWidth =
856
- (dataGridWidth - leftColumnWidth - bordersWidth) /
857
- headItemsPresent.value.length
858
-
859
- headItemsPresent.value.forEach((item) => {
860
- columnsWidth.value.push([
861
- `${columnWidth}px`, // width
862
- item.width, // min-width
863
- ])
864
- })
865
- }
866
- setColumnWidth = useThrottle(setColumnWidth)
867
-
868
- const columnsWidth = ref<[string, string][]>([])
869
- watch(
870
- bodyItemsPresent,
871
- (newValue: UI_I_BodyItem[][]) => {
872
- newValue.forEach(() => {
873
- toggedItems.value.push(false)
874
- })
875
- setColumnWidth()
876
- },
877
- {
878
- immediate: true,
879
- deep: true,
880
- }
881
- )
882
-
883
- watch(
884
- headItemsPresent,
885
- (newValue: UI_I_HeadItem[]) => {
886
- filterShow.value = newValue.map(() => false)
887
- filterTerm.value = newValue.map(() => '')
888
- },
889
- {
890
- immediate: true,
891
- deep: true,
892
- }
893
- )
894
-
895
- const grabColumn = ref<number>(-1)
896
- const grabStartX = ref<number>(0)
897
- const setGrab = (key: number, e: MouseEvent): void => {
898
- if (props.withInfo && key === 0) return
899
-
900
- if (!isShowHiddenInfo.value) {
901
- grabColumn.value = key
902
- const currentWidth = parseInt(columnsWidth.value[grabColumn.value][0])
903
- grabStartX.value = e.clientX - currentWidth
904
- }
905
- }
906
-
907
- const isDrag = ref<boolean>(false)
908
-
909
- const mouseup = (): void => {
910
- if (grabColumn.value === -1) {
911
- return
912
- }
913
-
914
- grabColumn.value = -1
915
- isDrag.value = false
916
- }
917
-
918
- let resizeObserve: ResizeObserver
919
- let mousemove = (e: MouseEvent): void => {
920
- if (grabColumn.value === -1) return
921
-
922
- e.preventDefault()
923
- isDrag.value = true
924
- resizeObserve.disconnect()
925
-
926
- const minWidth = parseInt(columnsWidth.value[grabColumn.value][1])
927
- const changeX = Math.max(e.clientX - grabStartX.value, minWidth)
928
-
929
- columnsWidth.value[grabColumn.value] = [`${changeX}px`, `${minWidth}px`]
930
- }
931
- mousemove = useThrottle(mousemove)
932
-
933
- const setResizeObserve = (): void => {
934
- const el = document.getElementById(outerWrapper)
935
-
936
- if (!el) {
937
- setTimeout(setResizeObserve, 0)
938
- return
939
- }
940
-
941
- resizeObserve = new ResizeObserver(setColumnWidth)
942
- resizeObserve.observe(el)
943
- }
944
-
945
- let resizeObserveWithInfo: ResizeObserver
946
-
947
- const setColumnWidthWithInfo = (ent: ResizeObserverEntry[]): void => {
948
- if (isShowHiddenInfo.value) {
949
- memoryWidth = columnsWidth.value[1][0]
950
- columnsWidth.value[1][0] = `${ent[0].contentBoxSize[0].inlineSize - 86}px`
951
- } else {
952
- columnsWidth.value[1][0] = memoryWidth
953
- }
954
- }
955
-
956
- const setResizeObserveWithInfo = (): void => {
957
- const el = document.querySelector('.datagrid')
958
-
959
- if (!el) {
960
- setTimeout(setResizeObserveWithInfo, 0)
961
- return
962
- }
963
-
964
- resizeObserveWithInfo = new ResizeObserver(setColumnWidthWithInfo)
965
- resizeObserveWithInfo.observe(el)
966
- }
967
-
968
- onMounted(() => {
969
- window.addEventListener('mousemove', mousemove)
970
- window.addEventListener('mouseup', mouseup)
971
-
972
- if (props.withInfo) {
973
- setResizeObserveWithInfo()
974
- }
975
-
976
- setResizeObserve()
977
- })
978
- onUnmounted(() => {
979
- window.removeEventListener('mouseup', mouseup)
980
- window.removeEventListener('mousemove', mousemove)
981
- })
982
- </script>
983
-
984
- <style scoped lang="scss">
985
- @import '~/assets/scss/common/mixins';
986
- .datagrid-outer-wrapper {
987
- @include flex($dir: row);
988
- padding-top: 12px;
989
- flex-grow: 1;
990
- overflow: auto;
991
-
992
- &.datagrid-outer-wrapper-opened-info {
993
- width: 35%;
994
- min-width: 195px;
995
- }
996
-
997
- & * {
998
- box-sizing: border-box;
999
- }
1000
-
1001
- & svg {
1002
- fill: var(--table-color);
1003
- }
1004
-
1005
- .datagrid-inner-wrapper {
1006
- @include flex($dir: column);
1007
- flex-grow: 1;
1008
- overflow: auto;
1009
-
1010
- .main-filter-content {
1011
- align-items: center;
1012
-
1013
- .filter-icon {
1014
- width: 16px;
1015
- height: 16px;
1016
- margin-right: 10px;
1017
- }
1018
- }
1019
- .datagrid {
1020
- overflow: auto;
1021
- flex: 1 1 auto;
1022
- border-radius: 0.125rem 0.125rem 0 0;
1023
- background-color: var(--block-view-bg-color);
1024
- border-color: var(--global-border-color);
1025
-
1026
- &.datagrid-opened-info {
1027
- border-radius: 0.125rem 0 0 0;
1028
- overflow-x: hidden;
1029
- }
1030
-
1031
- .datagrid-table-wrapper {
1032
- min-width: max-content;
1033
- display: flex;
1034
- flex: 1 1 auto;
1035
- min-height: 100%;
1036
-
1037
- .datagrid-table {
1038
- @include flex($dir: column);
1039
- flex: 1 1 auto;
1040
- align-content: flex-start;
1041
- position: relative;
1042
-
1043
- .datagrid-header {
1044
- position: sticky;
1045
- top: 0;
1046
- z-index: 501;
1047
- width: auto;
1048
-
1049
- .datagrid-row-scrollable {
1050
- flex-direction: row;
1051
-
1052
- .datagrid-column-separator {
1053
- user-select: none;
1054
-
1055
- &::after {
1056
- cursor: col-resize;
1057
- }
1058
- &.double-arrow-separator .datagrid-column-handle {
1059
- cursor: unset;
1060
- }
1061
- &.double-arrow-separator::after {
1062
- cursor: unset;
1063
- }
1064
- }
1065
- }
1066
-
1067
- .datagrid-row {
1068
- color: var(--table-color);
1069
- background-color: var(--block-view-bg-color);
1070
-
1071
- &.datagrid-selected {
1072
- background-color: var(--row-selected-bg-color);
1073
- border-bottom: 1px solid var(--global-border-color);
1074
-
1075
- & :deep(*) {
1076
- color: var(--table-active-color);
1077
- }
1078
- }
1079
-
1080
- .datagrid-column {
1081
- background-color: var(--block-view-bg-color);
1082
- border-bottom: 1px solid var(--global-border-color);
1083
- padding: 6px 12px 5px;
1084
- position: relative;
1085
- //flex: 1 1 auto;
1086
-
1087
- &:last-child {
1088
- flex: 1 1 auto;
1089
- }
1090
-
1091
- &.datagrid-toggle-block {
1092
- width: 38px;
1093
- min-width: 38px;
1094
-
1095
- .datagrid-column-separator {
1096
- cursor: default;
1097
-
1098
- &::after {
1099
- cursor: default;
1100
- }
1101
- }
1102
- }
1103
- }
1104
-
1105
- .datagrid-column-title {
1106
- align-self: auto;
1107
- color: var(--table-color);
1108
- background-color: var(--block-view-bg-color);
1109
- border-bottom-color: var(--global-border-color);
1110
- font-size: 11px;
1111
- @include flex($align: center);
1112
- display: flex;
1113
- flex-direction: row;
1114
- justify-content: flex-start;
1115
- align-items: center;
1116
- //line-height: 24px;
1117
- line-height: normal;
1118
-
1119
- .title-column {
1120
- font-weight: bold;
1121
- font-size: 11px;
1122
- overflow: hidden;
1123
- text-wrap: none;
1124
- text-overflow: ellipsis;
1125
- }
1126
-
1127
- .sort-arrow-wrap {
1128
- margin-left: auto;
1129
- height: 14px;
1130
- width: 14px;
1131
- min-height: 14px;
1132
- min-width: 14px;
1133
- vertical-align: middle;
1134
-
1135
- .sort-arrow {
1136
- &.down {
1137
- transform: rotate(180deg);
1138
- }
1139
- }
1140
- }
1141
- .title-icon {
1142
- width: 24px;
1143
- height: 24px;
1144
- }
1145
- }
1146
-
1147
- .datagrid-filter-toggle {
1148
- background: unset;
1149
- margin-top: -4px;
1150
- align-self: center;
1151
-
1152
- .filter-icon {
1153
- width: 16px;
1154
- height: 16px;
1155
- }
1156
- }
1157
- }
1158
- }
1159
-
1160
- .datagrid-placeholder-container {
1161
- .datagrid-placeholder.datagrid-empty {
1162
- background: var(--block-view-bg-color);
1163
- }
1164
- span {
1165
- font-size: 16px;
1166
- color: var(--global-font-color4);
1167
- }
1168
- }
1169
-
1170
- .datagrid-row {
1171
- width: 100%;
1172
- min-width: max-content;
1173
- border-top: none;
1174
- color: var(--table-color);
1175
- background-color: var(--block-view-bg-color);
1176
- border-bottom: 1px solid var(--global-border-color);
1177
-
1178
- &.datagrid-selected {
1179
- & :deep(*) {
1180
- color: var(--table-active-color);
1181
- }
1182
-
1183
- .datagrid-cell {
1184
- background-color: var(--row-selected-bg-color);
1185
- border-bottom: 1px solid var(--global-border-color);
1186
- position: relative;
1187
- line-height: 1rem;
1188
- }
1189
-
1190
- .datagrid-row-detail {
1191
- background-color: var(--row-selected-bg-color);
1192
- border-bottom: 1px solid var(--global-border-color);
1193
- }
1194
- }
1195
-
1196
- .datagrid-cell {
1197
- min-width: 38px;
1198
- min-height: 28px;
1199
- padding: 2px 12px 3px 12px;
1200
- position: relative;
1201
-
1202
- &:has(.double-arrow-wrap) {
1203
- padding-left: 4px;
1204
- }
1205
-
1206
- &:has(.double-arrow-wrap)::after {
1207
- content: '';
1208
- width: 0.5px;
1209
- height: calc(100% - 6px);
1210
- position: absolute;
1211
- right: 2px;
1212
- top: 3px;
1213
- background-color: var(--global-border-color);
1214
- }
1215
-
1216
- &:last-child {
1217
- flex: 1 1 auto;
1218
- }
1219
-
1220
- button {
1221
- height: 0.9rem;
1222
- width: 0.9rem;
1223
-
1224
- .arrow-icon {
1225
- width: 16px;
1226
- height: 16px;
1227
- transform: rotate(90deg);
1228
- }
1229
- }
1230
-
1231
- .datagrid-cell-icon {
1232
- display: inline-block;
1233
- width: 16px;
1234
- height: 16px;
1235
- }
1236
-
1237
- .datagrid-expandable-caret-button {
1238
- cursor: pointer;
1239
- width: 100%;
1240
-
1241
- .datagrid-expandable-caret-icon {
1242
- width: 16px;
1243
- height: 16px;
1244
- transform: rotate(90deg);
1245
- fill: var(--table-caret-color);
1246
-
1247
- &.toggle {
1248
- transform: rotate(180deg);
1249
- }
1250
- }
1251
- }
1252
- }
1253
-
1254
- &.datagrid-selected-info {
1255
- width: 100%;
1256
- min-width: max-content;
1257
- border-top: none;
1258
- color: var(--table-color);
1259
- background-color: var(--block-view-bg-color);
1260
-
1261
- .datagrid-cell {
1262
- position: relative;
1263
-
1264
- &.hidden-text-triangle::after {
1265
- content: '';
1266
- position: absolute;
1267
- transform: rotate(225deg);
1268
- border-bottom: 15px solid transparent;
1269
- border-right: 15px solid var(--global-bg-color);
1270
- bottom: 26%;
1271
- right: -16px;
1272
- z-index: 1000;
1273
- }
1274
-
1275
- &.hidden-text-triangle::before {
1276
- content: '';
1277
- transform: rotate(-135deg);
1278
- position: absolute;
1279
- border-bottom: 16px solid transparent;
1280
- border-right: 16px solid var(--global-border-color);
1281
- bottom: 23%;
1282
- right: -17px;
1283
- z-index: 999;
1284
- }
1285
- }
1286
- }
1287
- }
1288
-
1289
- .datagrid-row-sticky {
1290
- @include flex($w: nowrap);
1291
- position: sticky;
1292
- left: 0;
1293
- z-index: 500;
1294
- background-color: var(--block-view-bg-color);
1295
-
1296
- .datagrid-column {
1297
- color: var(--table-color);
1298
- background-color: var(--block-view-bg-color);
1299
- border-bottom-color: var(--global-border-color);
1300
- text-align: left;
1301
- display: flex;
1302
- flex: 1 1 auto;
1303
- vertical-align: top;
1304
- border: none;
1305
-
1306
- &.datagrid-expandable-caret {
1307
- .datagrid-column-separator {
1308
- display: block;
1309
-
1310
- &::after {
1311
- top: 0;
1312
- height: 18px;
1313
- }
1314
- }
1315
-
1316
- .radio-btn {
1317
- width: 16px;
1318
- height: 16px;
1319
- }
1320
- }
1321
-
1322
- .datagrid-column-separator {
1323
- position: relative;
1324
- //left: 0.6rem;
1325
- flex: 0 0 auto;
1326
- width: 0.05rem;
1327
- order: 100;
1328
- margin-left: auto;
1329
- height: 100%;
1330
- }
1331
- }
1332
-
1333
- .datagrid-fixed-column-without-separator {
1334
- background-color: var(--block-view-bg-color);
1335
-
1336
- &::after {
1337
- background-color: transparent;
1338
- }
1339
- }
1340
-
1341
- .datagrid-fixed-column {
1342
- background-color: var(--block-view-bg-color);
1343
-
1344
- &::after {
1345
- content: '';
1346
- width: 0.05rem;
1347
- height: calc(100% - 0.5rem);
1348
- position: absolute;
1349
- right: 0;
1350
- top: 0.25rem;
1351
- background-color: var(--global-border-color);
1352
- }
1353
-
1354
- .clr-form-control-disabled {
1355
- .clr-checkbox-wrapper {
1356
- label {
1357
- cursor: not-allowed;
1358
- }
1359
- }
1360
- }
1361
- }
1362
- }
1363
-
1364
- .datagrid-row-scrollable {
1365
- @include flex($ff: row nowrap);
1366
- flex: 1 1 auto;
1367
-
1368
- .datagrid-scrolling-cells {
1369
- @include flex($ff: row nowrap);
1370
- flex: 1 1 auto;
1371
- }
1372
- }
1373
- .datagrid-body-row {
1374
- .datagrid-row-scrollable {
1375
- @include flex($ff: column nowrap);
1376
-
1377
- .datagrid-row-detail {
1378
- flex: 1;
1379
- }
1380
- }
1381
-
1382
- &:not(.datagrid-selected):hover {
1383
- border-bottom: 1px solid var(--table-hover-row-border-color);
1384
- background-color: var(--table-hover-row-background-color);
1385
- color: var(--table-hover-row-color);
1386
-
1387
- .datagrid-fixed-column {
1388
- background-color: var(--table-hover-row-background-color);
1389
- }
1390
- .datagrid-cell {
1391
- background-color: var(--table-hover-row-background-color);
1392
- }
1393
- }
1394
- }
1395
- }
1396
- }
1397
- }
1398
-
1399
- .datagrid-footer {
1400
- flex: 0 0 auto;
1401
- @include flex($ff: row nowrap, $just: space-between, $align: stretch);
1402
- font-size: 0.55rem;
1403
- background-color: var(--block-view-bg-color);
1404
- border: 0.05rem solid var(--global-border-color);
1405
- border-top: none;
1406
- border-radius: 0 0 0.15rem 0.15rem;
1407
- padding: 0 0.6rem;
1408
- height: 28px;
1409
-
1410
- &.datagrid-footer-opened-info {
1411
- border-radius: 0 0 0 0.15rem;
1412
- flex-direction: row-reverse;
1413
- }
1414
-
1415
- .clr-form-control-disabled {
1416
- opacity: 1;
1417
-
1418
- .clr-checkbox-wrapper {
1419
- label {
1420
- color: #8c8c8c;
1421
- margin-right: 9px;
1422
- padding-left: 22px;
1423
- &:before {
1424
- position: absolute;
1425
- top: 4px;
1426
- left: 0;
1427
- content: '';
1428
- display: inline-block;
1429
- height: 16px;
1430
- width: 16px;
1431
- border: none;
1432
- border-radius: 3px;
1433
- background-color: var(--table-checkbox-color);
1434
- }
1435
-
1436
- &:after {
1437
- position: absolute;
1438
- content: '';
1439
- display: inline-block;
1440
- height: 5px;
1441
- width: 8px;
1442
- border-left: 2px solid #fff;
1443
- border-bottom: 2px solid #fff;
1444
- top: 4px;
1445
- left: 4px;
1446
- transform: translateY(4px) rotate(-45deg);
1447
- }
1448
- }
1449
- }
1450
- }
1451
- }
1452
-
1453
- .datagrid-spinner {
1454
- top: 0.6rem;
1455
- height: calc(100% - 0.6rem);
1456
- }
1457
-
1458
- .datagrid-footer-description {
1459
- flex: 1 1 auto;
1460
-
1461
- :deep(svg) {
1462
- fill: var(--table-switch-color);
1463
- }
1464
- }
1465
-
1466
- .clr-radio-wrapper,
1467
- .clr-checkbox-wrapper {
1468
- height: 18px;
1469
- }
1470
-
1471
- .clr-radio-wrapper label,
1472
- .clr-checkbox-wrapper label {
1473
- padding-left: 16px;
1474
- }
1475
- }
1476
- }
1477
- //.vertical-divider {
1478
- // width: 1px;
1479
- // height: 22px;
1480
- // background: #bbb;
1481
- // margin: 2px 2px 0 -5px;
1482
- //}
1483
-
1484
- .hidden-features {
1485
- padding: 9px 14px;
1486
- background-color: var(--global-bg-color);
1487
- color: var(--global-font-color2);
1488
- border: 1px solid var(--global-border-color);
1489
- border-left: none;
1490
- overflow-y: auto;
1491
- overflow-x: hidden;
1492
- width: 65%;
1493
-
1494
- .header {
1495
- display: flex;
1496
- align-items: center;
1497
- justify-content: space-between;
1498
- background-color: inherit;
1499
-
1500
- h3 {
1501
- font-size: 1rem;
1502
- color: var(--global-font-color2) !important;
1503
- line-height: 1.7rem;
1504
- }
1505
- button {
1506
- line-height: 24px;
1507
-
1508
- .close-icon {
1509
- margin-left: 10px;
1510
- width: 24px;
1511
- height: 24px;
1512
- }
1513
- }
1514
- }
1515
- }
1516
- .double-arrow-width {
1517
- width: 25px;
1518
- }
1519
- .double-arrow-wrap {
1520
- width: 30px;
1521
- height: 20px;
1522
- padding-top: 1px;
1523
- padding-left: 5px;
1524
- cursor: pointer;
1525
- background-color: transparent;
1526
-
1527
- .double-arrow {
1528
- background-color: transparent;
1529
- transform: rotate(90deg);
1530
- width: 16px;
1531
- height: 16px;
1532
- }
1533
-
1534
- .double-arrow.arrow-selected {
1535
- transform: rotate(-90deg) !important;
1536
- background-color: #0079b8;
1537
- }
1538
- }
1539
- .double-arrow-wrap.arrow-selected {
1540
- background-color: #0079b8;
1541
- border-radius: 3px;
1542
- }
1543
- </style>
1544
-
1545
- <style>
1546
- :root {
1547
- --table-color: #565656;
1548
- --table-active-color: #fff;
1549
- --table-checkbox-color: #454545;
1550
- --table-caret-color: #454545;
1551
- --table-switch-color: #575757;
1552
- --table-hover-row-border-color: #666;
1553
- --table-hover-row-background-color: #e8e8e8;
1554
- --table-hover-row-color: #454545;
1555
- --table-spinner-bg-color: #ffffff99;
1556
- }
1557
-
1558
- :root.dark-theme {
1559
- --table-color: #fff;
1560
- --table-active-color: #565656;
1561
- --table-checkbox-color: #49aeda;
1562
- --table-caret-color: #ffffff;
1563
- --table-switch-color: #b3b3b3;
1564
- --table-hover-row-border-color: #fff;
1565
- --table-hover-row-background-color: #324f61;
1566
- --table-hover-row-color: #e9ecef;
1567
- --table-spinner-bg-color: rgba(0, 0, 0, 0.5);
1568
- }
1569
- </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 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>