vgapp 1.4.9 → 1.5.0

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,6 +1,6 @@
1
1
  /**
2
- * Описание: базовая логика выбора, валидации и отображения файлов VGFiles.
3
- * Возможности: управляет набором файлов, ошибками, списками, статистикой и скрытыми полями формы.
2
+ * Описание: базовая логика выбора, валидации и отображения файлов VGFiles.
3
+ * Возможности: управляет набором файлов, ошибками, списками, кастомными действиями, статистикой и скрытыми полями формы.
4
4
  */
5
5
  import BaseModule from "../../base-module";
6
6
  import {mergeDeepObject} from "../../../utils/js/functions";
@@ -422,7 +422,7 @@ class VGFilesBase extends BaseModule {
422
422
  };
423
423
  }
424
424
 
425
- _renderUIDropList(files) {
425
+ _renderUIDropList(files) {
426
426
  if (!this._nodes.drop) return;
427
427
 
428
428
  let $list = Selectors.find(`.${this._getClass('drop-list')}`, this._nodes.drop);
@@ -435,9 +435,10 @@ class VGFilesBase extends BaseModule {
435
435
  const fragment = document.createDocumentFragment();
436
436
 
437
437
  files.forEach((file) => {
438
- let classes = $itemsTemplateClasses;
438
+ let classes = [...$itemsTemplateClasses];
439
439
 
440
- if (this._params.detach) classes.push('with-remove')
440
+ if (this._params.detach) classes.push('with-remove')
441
+ if (this._params.customButtons?.hideOnUploadState) classes.push('hide-custom-buttons-on-upload-state')
441
442
  if (this._params.sortable.enabled) classes.push('with-sortable')
442
443
  if (this._params.limits.count === 1) {
443
444
  classes.push('single');
@@ -606,12 +607,13 @@ class VGFilesBase extends BaseModule {
606
607
  return '';
607
608
  }
608
609
 
609
- _createInfoListItem(file, i, itemsTemplate, itemTemplateClasses, fileKey, signature) {
610
+ _createInfoListItem(file, i, itemsTemplate, itemTemplateClasses, fileKey, signature) {
610
611
  let classes = [...itemTemplateClasses];
611
612
 
612
613
  if (this._params.image) classes.push('with-image');
613
614
  if (this._params.info) classes.push('with-info');
614
- if (this._params.detach) classes.push('with-remove')
615
+ if (this._params.detach) classes.push('with-remove')
616
+ if (this._params.customButtons?.hideOnUploadState) classes.push('hide-custom-buttons-on-upload-state')
615
617
  if (this._params.sortable.enabled) classes.push('with-sortable');
616
618
  const previewPath = this._resolveFilePreviewPath(file);
617
619
  const displayName = this._resolveDisplayName(file);
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Описание: основной класс выбора, отображения и AJAX-загрузки файлов VGFiles.
3
- * Возможности: управляет списками и dropzone, прогрессом, удалением, повторной загрузкой и сортировкой.
3
+ * Возможности: управляет списками и dropzone, прогрессом, кастомными действиями, удалением, повторной загрузкой и сортировкой.
4
4
  */
5
5
  import VGFilesBase from "./base";
6
6
  import FileUploader from "./loader";
@@ -47,8 +47,11 @@ class VGFiles extends VGFilesBase {
47
47
  prepend: true,
48
48
  replace: true,
49
49
  rename: false,
50
- smartdrop: false,
51
- uploads: {
50
+ smartdrop: false,
51
+ customButtons: {
52
+ hideOnUploadState: true
53
+ },
54
+ uploads: {
52
55
  mode: 'sequential',
53
56
  route: '',
54
57
  maxParallel: 3,
@@ -23,8 +23,18 @@
23
23
  }
24
24
  }
25
25
 
26
- @mixin vgfiles-state() {
27
- &.pending {
26
+ @mixin vgfiles-state() {
27
+ &.hide-custom-buttons-on-upload-state {
28
+ &.pending,
29
+ &.loading,
30
+ &.failing {
31
+ .file-actions {
32
+ display: none;
33
+ }
34
+ }
35
+ }
36
+
37
+ &.pending {
28
38
  > * {
29
39
  opacity: .32;
30
40
  pointer-events: none;
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Описание: разметка Fixed Header с отдельными слоями заголовка и тела VGTable.
3
- * Возможности: перенос настоящего thead без клона, синхронизация колонок и горизонтальной прокрутки.
3
+ * Возможности: перенос настоящего thead без клона, синхронизация ширин колонок и горизонтальной прокрутки.
4
4
  */
5
5
 
6
6
  const MODE_CLASSES = ['vg-table-wrapper--sticky-container', 'vg-table-wrapper--sticky-page'];
@@ -19,8 +19,9 @@ class _stickyHeader {
19
19
  this._headerTable = null;
20
20
  this._body = null;
21
21
  this._previousClasses = new Map();
22
- this._previousContainerClasses = new Map();
23
- this._previousStyles = new Map();
22
+ this._previousContainerClasses = new Map();
23
+ this._previousStyles = new Map();
24
+ this._previousHeaderWidths = new Map();
24
25
  this._boundScroll = this._syncScroll.bind(this);
25
26
  this._boundResize = this.refresh.bind(this);
26
27
  this._boundPageScroll = this._syncStickyState.bind(this);
@@ -68,9 +69,10 @@ class _stickyHeader {
68
69
  refresh() {
69
70
  if (!this._header || !this._headerTable || !this._body) return this;
70
71
 
71
- const widths = this._measureBodyColumns();
72
- this._applyColgroup(this._headerTable, widths);
73
- this._applyColgroup(this._element, widths);
72
+ const widths = this._measureBodyColumns();
73
+ this._applyColgroup(this._headerTable, widths);
74
+ this._applyColgroup(this._element, widths);
75
+ this._applyHeaderWidths(widths);
74
76
  const scrollbar = Math.max(0, this._body.offsetWidth - this._body.clientWidth);
75
77
  this._header.style.paddingInlineEnd = `${scrollbar}px`;
76
78
  this._header.style.setProperty('--vg-table-sticky-scrollbar-width', `${scrollbar}px`);
@@ -101,12 +103,16 @@ class _stickyHeader {
101
103
  CONTAINER_MODE_CLASSES.forEach((className) => {
102
104
  this._container.classList.toggle(className, this._previousContainerClasses.get(className) === true);
103
105
  });
104
- STYLE_PROPERTIES.forEach((property) => {
106
+ STYLE_PROPERTIES.forEach((property) => {
105
107
  const previous = this._previousStyles.get(property);
106
108
  if (previous) this._container.style.setProperty(property, previous);
107
109
  else this._container.style.removeProperty(property);
108
- });
109
- this._element.removeAttribute('data-vg-table-sticky-header');
110
+ });
111
+ this._previousHeaderWidths.forEach((width, cell) => {
112
+ cell.style.width = width;
113
+ });
114
+ this._previousHeaderWidths.clear();
115
+ this._element.removeAttribute('data-vg-table-sticky-header');
110
116
  }
111
117
 
112
118
  _buildLayers(widths) {
@@ -131,16 +137,22 @@ class _stickyHeader {
131
137
  this._body.append(this._element);
132
138
  }
133
139
 
134
- _measureColumns() {
135
- const row = this._element.tBodies[0]?.rows[0] || this._head.rows[this._head.rows.length - 1];
136
- return this._measureRow(row);
137
- }
138
-
139
- _measureBodyColumns() {
140
- const row = this._element.tBodies[0]?.rows[0];
141
- const widths = this._measureRow(row);
142
- return widths.some((width) => width > 0) ? widths : this._measureRow(this._head.rows[this._head.rows.length - 1]);
143
- }
140
+ _measureColumns() {
141
+ return this._measureBodyColumns();
142
+ }
143
+
144
+ _measureBodyColumns() {
145
+ const headerRow = this._head?.rows[this._head.rows.length - 1];
146
+ const headerWidths = this._measureRow(headerRow);
147
+ const rows = Array.from(this._element.tBodies || []).flatMap((body) => Array.from(body.rows || []));
148
+ for (const row of rows) {
149
+ if (row.hidden || row.hasAttribute('data-vg-table-state-row') || row.hasAttribute('data-vg-table-skeleton') || row.hasAttribute('data-vg-table-skeleton-row')) continue;
150
+ if (row.querySelector('[data-vg-table-state]')) continue;
151
+ const widths = this._measureRow(row);
152
+ if (widths.length === headerWidths.length && widths.some((width) => width > 0)) return widths;
153
+ }
154
+ return headerWidths;
155
+ }
144
156
 
145
157
  _measureRow(row) {
146
158
  if (!row) return [];
@@ -151,7 +163,7 @@ class _stickyHeader {
151
163
  });
152
164
  }
153
165
 
154
- _applyColgroup(table, widths) {
166
+ _applyColgroup(table, widths) {
155
167
  if (!widths.length) return;
156
168
  if (table.querySelector(':scope > colgroup:not([data-vg-table-sticky-colgroup])')) return;
157
169
  let colgroup = table.querySelector(':scope > colgroup[data-vg-table-sticky-colgroup]');
@@ -164,8 +176,21 @@ class _stickyHeader {
164
176
  const col = table.ownerDocument.createElement('col');
165
177
  if (width > 0) col.style.width = `${width}px`;
166
178
  return col;
167
- }));
168
- }
179
+ }));
180
+ }
181
+
182
+ _applyHeaderWidths(widths) {
183
+ const row = this._head?.rows[this._head.rows.length - 1];
184
+ if (!row || !widths.length) return;
185
+ let columnIndex = 0;
186
+ Array.from(row.cells).forEach((cell) => {
187
+ if (!this._previousHeaderWidths.has(cell)) this._previousHeaderWidths.set(cell, cell.style.width);
188
+ const span = Math.max(1, cell.colSpan || 1);
189
+ const width = widths.slice(columnIndex, columnIndex + span).reduce((total, value) => total + value, 0);
190
+ if (width > 0) cell.style.width = `${width}px`;
191
+ columnIndex += span;
192
+ });
193
+ }
169
194
 
170
195
  _syncScroll() {
171
196
  if (this._header && this._body) this._header.scrollLeft = this._body.scrollLeft;
@@ -23,17 +23,18 @@
23
23
  border-radius: var(--vg-table-sticky-radius);
24
24
  background: var(--vg-table-sticky-bg);
25
25
 
26
- .vg-table-header,
27
- .vg-table-body {
28
- width: 100%;
29
- }
30
-
31
- .vg-table-header {
32
- position: relative;
33
- overflow: hidden;
34
- background: var(--vg-table-thead-bg);
35
- border-start-start-radius: var(--vg-table-sticky-inner-radius);
36
- border-start-end-radius: var(--vg-table-sticky-inner-radius);
26
+ .vg-table-header,
27
+ .vg-table-body {
28
+ width: 100%;
29
+ }
30
+
31
+ .vg-table-header {
32
+ position: relative;
33
+ z-index: var(--vg-table-sticky-z-index);
34
+ overflow: hidden;
35
+ background: var(--vg-table-thead-bg);
36
+ border-start-start-radius: var(--vg-table-sticky-inner-radius);
37
+ border-start-end-radius: var(--vg-table-sticky-inner-radius);
37
38
 
38
39
  &--scrollbar::after {
39
40
  content: "";
@@ -46,11 +47,16 @@
46
47
  border-bottom: var(--vg-table-sticky-border-width) var(--vg-table-sticky-border-style) var(--vg-table-sticky-border-color);
47
48
  background: var(--vg-table-fixed-header-bg, var(--vg-table-thead-bg));
48
49
  pointer-events: none;
49
- }
50
- }
51
-
52
- .vg-table-header__table,
53
- .vg-table-body > .vg-table {
50
+ }
51
+ }
52
+
53
+ .vg-table-body {
54
+ position: relative;
55
+ z-index: 0;
56
+ }
57
+
58
+ .vg-table-header__table,
59
+ .vg-table-body > .vg-table {
54
60
  width: 100%;
55
61
  min-width: 100%;
56
62
  table-layout: fixed;
@@ -114,8 +120,8 @@
114
120
  }
115
121
  }
116
122
 
117
- .vg-table-body {
118
- overflow: visible;
119
- }
120
- }
121
- }
123
+ .vg-table-body {
124
+ overflow: auto;
125
+ }
126
+ }
127
+ }