mediacube-ui 0.1.366 → 0.1.368

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [0.1.368](https://github.com/MediaCubeCo/mcui/compare/v0.1.367...v0.1.368) (2025-03-25)
6
+
7
+ ### [0.1.367](https://github.com/MediaCubeCo/mcui/compare/v0.1.366...v0.1.367) (2025-03-24)
8
+
5
9
  ### [0.1.366](https://github.com/MediaCubeCo/mcui/compare/v0.1.365...v0.1.366) (2025-03-18)
6
10
 
7
11
  ### [0.1.365](https://github.com/MediaCubeCo/mcui/compare/v0.1.364...v0.1.365) (2025-03-17)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mediacube-ui",
3
- "version": "0.1.366",
3
+ "version": "0.1.368",
4
4
  "description": "Design system for Mediacube services",
5
5
  "author": "Mediacube",
6
6
  "private": false,
@@ -23,10 +23,10 @@
23
23
  <component
24
24
  :is="tag"
25
25
  v-bind="attrs"
26
+ :empty-render="{ name: 'noData' }"
26
27
  v-on="{ ...$listeners, 'sort-change': handleSort }"
27
- @scroll="handleScroll"
28
28
  @context-menu-click="contextMenuClickEvent"
29
- :empty-render="{ name: 'noData' }"
29
+ @scroll="handleScroll"
30
30
  >
31
31
  <!-- @slot Слот дочерних mc-table-col -->
32
32
  <slot />
@@ -44,7 +44,11 @@
44
44
  </component>
45
45
  <div v-if="sortLoading || $attrs.loading" :class="footerClasses" class="mc-table-wrapper__footer">
46
46
  <div v-if="footerInfo !== 'total'" class="mc-table-wrapper__tint"></div>
47
- <div v-if="($attrs.loading && scrollIsBottom) || sortLoading" class="mc-table-wrapper__loading">
47
+ <div
48
+ v-if="($attrs.loading && scrollIsBottom) || sortLoading"
49
+ :style="loadingWrapperStyle"
50
+ class="mc-table-wrapper__loading"
51
+ >
48
52
  <mc-svg-icon class="mc-table-wrapper__load-icon" name="loader" />
49
53
  <mc-title color="outline-gray">{{ placeholders.loading }}</mc-title>
50
54
  </div>
@@ -63,6 +67,7 @@ import McTitle from '../../../elements/McTitle/McTitle'
63
67
  import McSvgIcon from '../../../elements/McSvgIcon/McSvgIcon'
64
68
  import McTableCol from '../McTableCol/McTableCol'
65
69
  import McOverlay from '../../McOverlay/McOverlay.vue'
70
+ import McInfinityLoadingIndicator from 'mediacube-ui/src/elements/McInfinityLoadingIndicator/McInfinityLoadingIndicator.vue'
66
71
 
67
72
  /**
68
73
  * More info: https://xuliangzhan.com/vxe-table, https://xuliangzhan.github.io/vxe-table
@@ -70,6 +75,7 @@ import McOverlay from '../../McOverlay/McOverlay.vue'
70
75
  export default {
71
76
  name: 'McTable',
72
77
  components: {
78
+ McInfinityLoadingIndicator,
73
79
  McTitle,
74
80
  McSvgIcon,
75
81
  McTableCol,
@@ -106,6 +112,14 @@ export default {
106
112
  type: Boolean,
107
113
  default: false,
108
114
  },
115
+ fixedFirstColumn: {
116
+ type: Boolean,
117
+ default: false,
118
+ },
119
+ fixedLastColumn: {
120
+ type: Boolean,
121
+ default: false,
122
+ },
109
123
  /**
110
124
  * Тип таблицы:
111
125
  * `table, grid`
@@ -277,6 +291,8 @@ export default {
277
291
  firstColsWidth: 253,
278
292
  hasHorizontalScroll: false,
279
293
  scrollIsBottom: false,
294
+ tableBodyScrollLeft: false,
295
+ tableBodyScrollRight: true,
280
296
  }
281
297
  },
282
298
  computed: {
@@ -286,10 +302,12 @@ export default {
286
302
  attrs() {
287
303
  const attrs = {
288
304
  ref: 'xTable',
305
+ data: this.items,
306
+ 'merge-cells': this.mergeCells,
289
307
  'context-menu': this.tableMenu,
290
308
  class: this.classes,
291
309
  'sync-resize': this.cardIsOpen,
292
- 'scroll-y': this.scrollY,
310
+ 'scroll-y': { ...this.scrollY, offset: 30, mode: 'slide' },
293
311
  'show-footer': this.canShowFooter,
294
312
  'footer-method': this.footerMethod,
295
313
  'sort-config': {
@@ -302,6 +320,7 @@ export default {
302
320
  theme: 'mcui-black',
303
321
  },
304
322
  'row-id': 'id',
323
+ 'key-field': 'id',
305
324
  'highlight-hover-row': !this.skeletonLoad,
306
325
  'highlight-current-row': true,
307
326
  'show-header-overflow': 'tooltip',
@@ -315,6 +334,11 @@ export default {
315
334
  }
316
335
  return attrs
317
336
  },
337
+ loadingWrapperStyle() {
338
+ return {
339
+ width: this.cardIsOpen ? `${this.firstColsWidth}px` : '100%',
340
+ }
341
+ },
318
342
  canShowLoader() {
319
343
  return !this.scrollable && this.hasMore
320
344
  },
@@ -338,6 +362,10 @@ export default {
338
362
  'mc-table--clickable': this.$listeners['cell-click'],
339
363
  'mc-table--header-break-word': this.headerBreakWord,
340
364
  'mc-table--mono-font': this.monoFont,
365
+ 'mc-table--fixed-first-col': this.fixedFirstColumn,
366
+ 'mc-table--fixed-last-col': this.fixedLastColumn,
367
+ 'mc-table--scrolled-left-x-axis': !!this.tableBodyScrollLeft,
368
+ 'mc-table--scrolled-right-x-axis': !!this.tableBodyScrollRight,
341
369
  }
342
370
  },
343
371
  wrapperStyles() {
@@ -380,37 +408,21 @@ export default {
380
408
  },
381
409
  },
382
410
  watch: {
383
- canShowFooter(newValue) {
384
- newValue && this.updateData()
385
- },
386
- totalFooter: {
387
- handler: async function(newVal) {
388
- newVal && (await this.loadData(true))
389
- },
390
- deep: true,
391
- },
392
- items: {
393
- handler: async function(newVal, oldVal) {
394
- if (_isEqual(newVal, oldVal)) return
395
- if (newVal.length !== oldVal.length) {
396
- newVal && (await this.loadData(true))
397
- } else {
398
- newVal && (await this.setFirstColsWidth())
399
- await this.reloadData()
400
- }
401
- },
402
- deep: true,
403
- },
404
411
  cardIsOpen(newVal) {
405
412
  this.toggleColumns(newVal)
406
413
  },
407
414
  '$attrs.loading'() {
408
415
  this.checkHorizontalScroll()
409
416
  },
417
+ totalFooter() {
418
+ if (this.footerInfo === 'total') {
419
+ this.$nextTick(() => {
420
+ this.api.updateFooter()
421
+ })
422
+ }
423
+ },
410
424
  },
411
425
  mounted() {
412
- this.loadData()
413
- !this.scrollable && this.createObserver()
414
426
  this.setFirstColsWidth()
415
427
  window.addEventListener('resize', this.checkHorizontalScroll)
416
428
  },
@@ -419,34 +431,6 @@ export default {
419
431
  window.removeEventListener('resize', this.checkHorizontalScroll)
420
432
  },
421
433
  methods: {
422
- async loadData(force = false) {
423
- if ((this.items && this.items.length) || force) {
424
- await this.$refs.xTable.loadData(this.items)
425
- !this.scrollable && this.setObserveElement()
426
- this.hasMore && this.checkOccupancy()
427
- // После обновления данных в таблице обязательно мержим ячейки, если они указаны
428
- if (this.mergeCells?.length) this.$refs.xTable.setMergeCells(this.mergeCells)
429
- }
430
- },
431
- async reloadData() {
432
- // Доастаем отсортированную колонку и выполняем сортировку вручную, чтобы предотвратить сброс на релоаде
433
- const [sortState] = this.$refs.xTable.getSortColumns() || []
434
- await this.$refs.xTable.reloadData(this.items)
435
- if (sortState) {
436
- this.$refs.xTable.sort(sortState.property, sortState.order)
437
- }
438
- },
439
- async updateData() {
440
- await this.$refs.xTable.updateData()
441
- },
442
- checkOccupancy() {
443
- if (!this.$refs.xTable || !this.items?.length) return
444
- const tableHeight = this.$refs.xTable.$el.getBoundingClientRect().height
445
- const tableDataHeight = this.$refs.xTable.rowHeight * this.items.length
446
- if (tableHeight >= tableDataHeight) {
447
- this.load()
448
- }
449
- },
450
434
  formattedNumber(value, decimals = 2, is_rtl = false) {
451
435
  if (value == null) return null
452
436
 
@@ -473,14 +457,6 @@ export default {
473
457
  }),
474
458
  ]
475
459
  },
476
- handleScroll: _throttle(function({ scrollTop, $event, type, isY, $table }) {
477
- const bottomPos = Math.ceil($event.target.scrollHeight - $event.target.clientHeight)
478
- const isLoadArea = bottomPos - scrollTop <= $table._data.rowHeight * this.rowsToStartLoad
479
- this.scrollIsBottom = scrollTop / bottomPos > 0.95
480
- if (isLoadArea && !this.$attrs.loading && this.hasMore && type === 'body' && isY) {
481
- this.load()
482
- }
483
- }, 200),
484
460
  load() {
485
461
  /**
486
462
  * Событие по подгрузке данных
@@ -488,22 +464,24 @@ export default {
488
464
  */
489
465
  this.$emit('load')
490
466
  },
491
- createObserver() {
492
- this.observer = new IntersectionObserver(
493
- entries => {
494
- const entry = entries[0]
495
- if (entry.isIntersecting) {
496
- this.load()
497
- }
498
- },
499
- { threshold: 0.1 },
500
- )
501
- this.setObserveElement()
502
- },
503
- setObserveElement() {
504
- const loader = this.$refs.xTable.$el.getElementsByClassName('mc-table-col__loader')
505
- this.observer && loader.length && this.observer.observe(loader[0])
467
+ handleScroll({ $event, type, isY, isX }) {
468
+ if (type === 'body' && isX) {
469
+ this.tableBodyScrollLeft = !!$event.target.scrollLeft
470
+ this.tableBodyScrollRight =
471
+ $event.target.scrollLeft + $event.target.clientWidth < $event.target.scrollWidth
472
+ }
473
+ if (type === 'body' && isY) {
474
+ this.checkVerticalScroll(...arguments)
475
+ }
506
476
  },
477
+ checkVerticalScroll: _throttle(function({ scrollTop, $event, type, isY, isX, $table }) {
478
+ const bottomPos = Math.ceil($event.target.scrollHeight - $event.target.clientHeight)
479
+ const isLoadArea = bottomPos - scrollTop <= $table._data.rowHeight * this.rowsToStartLoad
480
+ this.scrollIsBottom = scrollTop / bottomPos > 0.95
481
+ if (isLoadArea && !this.$attrs.loading && this.hasMore) {
482
+ this.load()
483
+ }
484
+ }, 200),
507
485
  setFirstColsWidth() {
508
486
  const columns = this.$refs.xTable.getColumns()
509
487
  const leftFixedColumnsWidth = columns.reduce((sum, curr) => {
@@ -525,14 +503,17 @@ export default {
525
503
  toggleColumns(val) {
526
504
  if (val) {
527
505
  const columns = this.$refs.xTable.getColumns()
528
- const hideColumns = columns.filter(col => col.fixed !== 'left')
506
+ const hideColumns = this.fixedFirstColumn
507
+ ? columns.filter((c, i) => !!i)
508
+ : columns.filter(col => col.fixed !== 'left')
529
509
  hideColumns.forEach(col => (col.visible = false))
510
+ this.tableBodyScrollLeft = false
530
511
  this.$refs.xTable.refreshColumn()
531
512
  } else {
532
513
  this.$refs.xTable.resetColumn()
533
514
  }
534
- this.$refs.xTable.recalculate()
535
- this.$refs.xTable.syncData() // Синхронит данные таблиц (фикс колонка === отдельная таблица)
515
+ // this.$refs.xTable.recalculate()
516
+ // this.$refs.xTable.syncData() // Синхронит данные таблиц (фикс колонка === отдельная таблица)
536
517
  this.checkHorizontalScroll()
537
518
  },
538
519
  getFixedHeight(val) {
@@ -592,6 +573,7 @@ export default {
592
573
  @import '../../../styles/mixins';
593
574
  @import '../../../tokens/font-families';
594
575
  @import '../../../tokens/animations';
576
+ @import '../../../tokens/z-indexes';
595
577
 
596
578
  @import '~vxe-table/styles/variable.scss';
597
579
 
@@ -601,10 +583,12 @@ export default {
601
583
 
602
584
  .vxe-table {
603
585
  font-family: $font-family-main;
586
+
604
587
  &--tooltip-wrapper {
605
588
  .vxe-table--tooltip-content {
606
589
  white-space: normal;
607
590
  }
591
+
608
592
  &.theme--mcui-black {
609
593
  background: $color-black;
610
594
  color: $color-white;
@@ -617,26 +601,39 @@ export default {
617
601
  padding: $space-100 $space-150;
618
602
  }
619
603
  }
604
+
620
605
  .vxe-body--row.row--cheched {
621
606
  background-color: var(--color-main-alpha-10);
622
607
  }
608
+
623
609
  .fixed-left--wrapper {
624
610
  scrollbar-width: none;
625
611
  }
612
+
613
+ &--empty-block {
614
+ display: block !important;
615
+ height: 1px;
616
+ min-height: 1px !important;
617
+ }
626
618
  }
619
+
627
620
  .mc-table-wrapper {
628
621
  position: relative;
622
+
629
623
  &__footer {
630
624
  @include position(absolute, null 0 0 0);
631
- z-index: 2;
625
+ z-index: 3;
626
+
632
627
  &--indent-bottom {
633
628
  bottom: 5px;
634
629
  }
635
630
  }
631
+
636
632
  &__tint {
637
633
  height: $size-900;
638
634
  background: linear-gradient(0deg, $color-white 0%, rgba(255, 255, 255, 0) 100%);
639
635
  }
636
+
640
637
  &__loading {
641
638
  display: flex;
642
639
  align-items: center;
@@ -645,13 +642,16 @@ export default {
645
642
  background-color: $color-white;
646
643
  color: $color-outline-gray;
647
644
  @include child-indent-right($space-100);
645
+
648
646
  .mc-title {
649
647
  width: auto;
650
648
  }
651
649
  }
650
+
652
651
  &__load-icon {
653
652
  animation: $animation-spinner;
654
653
  }
654
+
655
655
  .skeleton-load {
656
656
  &-wrapper {
657
657
  display: flex;
@@ -659,7 +659,7 @@ export default {
659
659
  max-width: 100%;
660
660
  position: absolute;
661
661
  height: 100%;
662
- z-index: 19;
662
+ z-index: $z-index-modal;
663
663
  background-color: $color-white;
664
664
  user-select: none;
665
665
  }
@@ -674,11 +674,13 @@ export default {
674
674
  padding: $space-50 0;
675
675
  }
676
676
  }
677
+
677
678
  .vxe-body--row {
678
679
  font-feature-settings: 'tnum';
679
680
  font-variant-numeric: tabular-nums;
680
681
  }
681
682
  }
683
+
682
684
  .vxe-table--footer {
683
685
  .vxe-footer--row {
684
686
  font-feature-settings: 'tnum';
@@ -686,16 +688,121 @@ export default {
686
688
  }
687
689
  }
688
690
  }
691
+
692
+ &--fixed-first-col {
693
+ .vxe-header--row,
694
+ .vxe-body--row,
695
+ .vxe-footer--row {
696
+ td:first-child,
697
+ th:first-child {
698
+ position: sticky;
699
+ left: 0;
700
+ background-color: white;
701
+ z-index: 3;
702
+ }
703
+ }
704
+
705
+ .vxe-footer--row {
706
+ td {
707
+ border-block-start: 1px solid $color-hover-gray;
708
+ }
709
+ }
710
+ }
711
+
712
+ &--fixed-last-col {
713
+ .vxe-header--row,
714
+ .vxe-body--row,
715
+ .vxe-footer--row {
716
+ td:last-child,
717
+ th:last-child {
718
+ position: sticky;
719
+ right: 0;
720
+ background-color: white;
721
+ z-index: 3;
722
+
723
+ &:empty {
724
+ display: none;
725
+ }
726
+ }
727
+ }
728
+
729
+ .vxe-footer--row {
730
+ td {
731
+ border-block-start: 1px solid $color-hover-gray;
732
+ }
733
+ }
734
+ }
735
+
736
+ &--scrolled-left-x-axis {
737
+ &.mc-table--fixed-first-col {
738
+ .vxe-header--row,
739
+ .vxe-body--row,
740
+ .vxe-footer--row {
741
+ td:first-child,
742
+ th:first-child {
743
+ &::after {
744
+ content: '';
745
+ position: absolute;
746
+ top: 0;
747
+ left: 100%;
748
+ width: 12px;
749
+ height: 100%;
750
+ background: linear-gradient(to left, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.12) 100%);
751
+ }
752
+ }
753
+ }
754
+ }
755
+ }
756
+
757
+ &--scrolled-right-x-axis {
758
+ &.mc-table--fixed-last-col {
759
+ .vxe-header--row,
760
+ .vxe-body--row,
761
+ .vxe-footer--row {
762
+ td:last-child,
763
+ th:last-child {
764
+ &::after {
765
+ content: '';
766
+ position: absolute;
767
+ top: 0;
768
+ right: 100%;
769
+ width: 12px;
770
+ height: 100%;
771
+ background: linear-gradient(to right, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.12) 100%);
772
+ }
773
+ }
774
+ }
775
+ }
776
+ }
777
+
778
+ .vxe-body--row {
779
+ &.row--current {
780
+ td,
781
+ th {
782
+ background-color: color-mix(in srgb, var(--color-main) 10%, #fff 90%) !important;
783
+ }
784
+ }
785
+
786
+ &:hover {
787
+ td,
788
+ th {
789
+ background-color: $color-hover-gray;
790
+ }
791
+ }
792
+ }
793
+
689
794
  &--open-card {
690
795
  .vxe-table--body-wrapper,
691
796
  .vxe-table--footer-wrapper {
692
797
  overflow-x: hidden;
693
798
  width: fit-content;
694
799
  }
800
+
695
801
  .vxe-table--footer {
696
802
  display: none;
697
803
  }
698
804
  }
805
+
699
806
  &--clickable {
700
807
  .vxe-table--body {
701
808
  .vxe-body--row {
@@ -703,6 +810,7 @@ export default {
703
810
  }
704
811
  }
705
812
  }
813
+
706
814
  &--header-break-word {
707
815
  .vxe-header--column {
708
816
  .vxe-cell--title {
@@ -713,12 +821,15 @@ export default {
713
821
  }
714
822
  }
715
823
  }
824
+
716
825
  &__context-menu {
717
826
  width: 250px;
827
+
718
828
  .vxe-context-menu--link {
719
829
  width: 100%;
720
830
  }
721
831
  }
832
+
722
833
  .vxe-header--row {
723
834
  .col--checkbox {
724
835
  .vxe-cell {
@@ -728,13 +839,16 @@ export default {
728
839
  }
729
840
  }
730
841
  }
842
+
731
843
  .vxe-cell--checkbox {
732
844
  z-index: 1;
845
+
733
846
  &:hover {
734
847
  .vxe-checkbox--icon::before {
735
848
  border-color: var(--color-main) !important;
736
849
  }
737
850
  }
851
+
738
852
  &.is--checked,
739
853
  &.is--indeterminate {
740
854
  .vxe-checkbox--icon::before {
@@ -743,6 +857,7 @@ export default {
743
857
  }
744
858
  }
745
859
  }
860
+
746
861
  .vxe-header--column {
747
862
  .vxe-cell {
748
863
  &--title {
@@ -750,22 +865,31 @@ export default {
750
865
  align-items: center;
751
866
  }
752
867
  }
868
+
753
869
  &.is--sortable {
754
870
  cursor: pointer;
755
871
  }
756
872
  }
873
+
757
874
  .vxe-table--footer {
758
875
  border-bottom: 1px solid $color-hover-gray;
876
+
877
+ &-wrapper {
878
+ border: none;
879
+ }
759
880
  }
881
+
760
882
  .vxe-cell {
761
883
  padding-inline-start: $space-200;
762
884
  padding-inline-end: $space-200;
763
885
  word-break: break-word;
886
+
764
887
  &--checkbox {
765
888
  display: flex;
766
889
  align-items: center;
767
890
  max-width: 100%;
768
891
  padding-inline-start: 1.8em;
892
+
769
893
  .vxe-checkbox--icon {
770
894
  margin-inline-end: $space-50;
771
895
  top: 50%;
@@ -773,8 +897,10 @@ export default {
773
897
  }
774
898
  }
775
899
  }
900
+
776
901
  @include custom-scroll();
777
902
  }
903
+
778
904
  @mixin gradient() {
779
905
  background: $color-hover-gray;
780
906
  background-image: -webkit-gradient(
@@ -803,6 +929,7 @@ export default {
803
929
  margin: 0 auto;
804
930
  width: 100%;
805
931
  overflow: hidden;
932
+
806
933
  &:after {
807
934
  content: '';
808
935
  position: absolute;
@@ -811,12 +938,14 @@ export default {
811
938
  }
812
939
  }
813
940
  }
941
+
814
942
  .loader {
815
943
  width: 100%;
816
944
  display: flex;
817
945
  align-items: center;
818
946
  height: $space-500;
819
947
  padding: $space-100 $space-200;
948
+
820
949
  .avatar {
821
950
  display: block;
822
951
  float: left;
@@ -827,12 +956,14 @@ export default {
827
956
  margin-inline-end: $space-50;
828
957
  @include gradient();
829
958
  }
959
+
830
960
  .preview-content {
831
961
  display: flex;
832
962
  flex-direction: column;
833
963
  width: 100%;
834
964
  @include child-indent-bottom($space-50);
835
965
  }
966
+
836
967
  .line {
837
968
  display: block;
838
969
  position: relative;
@@ -840,6 +971,7 @@ export default {
840
971
  width: 100%;
841
972
  @include gradient();
842
973
  }
974
+
843
975
  &--more-height {
844
976
  .line {
845
977
  height: 12px;
@@ -244,6 +244,9 @@ export default {
244
244
  width: $size-300;
245
245
  background: linear-gradient(90deg, hsla(0, 0%, 100%, 0) 0, $color-white);
246
246
  }
247
+ &:empty {
248
+ display: none;
249
+ }
247
250
  }
248
251
  &__header-right {
249
252
  @extend .mc-table-col__right;