vgapp 1.5.3 → 1.5.5
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/app/modules/vgtable/js/_sticky-header.js +93 -15
- package/app/modules/vgtable/js/vgtable.js +12 -11
- package/app/modules/vgtable/scss/_sticky-header.scss +3 -3
- package/build/vgapp.css +1 -1
- package/build/vgapp.css.map +1 -1
- package/build/vgapp.js +1 -1
- package/build/vgapp.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Описание: разметка Fixed Header с отдельными слоями заголовка и тела VGTable.
|
|
3
|
-
* Возможности: перенос настоящего thead без клона,
|
|
3
|
+
* Возможности: перенос настоящего thead без клона, intrinsic-минимумы и синхронизация ширин колонок и горизонтальной прокрутки.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
const MODE_CLASSES = ['vg-table-wrapper--sticky-container', 'vg-table-wrapper--sticky-page'];
|
|
7
7
|
const CONTAINER_MODE_CLASSES = ['vg-table-container--sticky-container', 'vg-table-container--sticky-page'];
|
|
8
|
-
const
|
|
8
|
+
const CONTENT_MIN_WIDTH_PROPERTY = '--vg-table-sticky-content-min-width';
|
|
9
|
+
const STYLE_PROPERTIES = ['--vg-table-sticky-top', '--vg-table-sticky-max-height', CONTENT_MIN_WIDTH_PROPERTY];
|
|
9
10
|
const GENERATED_LAYER_ATTRIBUTE = 'data-vg-table-sticky-generated';
|
|
10
11
|
|
|
11
12
|
class _stickyHeader {
|
|
@@ -67,22 +68,39 @@ class _stickyHeader {
|
|
|
67
68
|
return this._headerTable || this._element;
|
|
68
69
|
}
|
|
69
70
|
|
|
70
|
-
getBody() {
|
|
71
|
-
return this._body;
|
|
72
|
-
}
|
|
71
|
+
getBody() {
|
|
72
|
+
return this._body;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
refreshIntrinsicMinimums() {
|
|
76
|
+
const widths = this._measureIntrinsicColumnMinimums();
|
|
77
|
+
this._getHeaders().forEach((header, index) => {
|
|
78
|
+
const key = this._columnKey(header, index);
|
|
79
|
+
if (this._hasDeclaredWidth(header) || this._hardColumnWidths.has(key) || !(widths[index] > 0)) return;
|
|
80
|
+
this._columnMinimumWidths.set(key, Math.max(this._columnMinimumWidths.get(key) || 0, widths[index]));
|
|
81
|
+
});
|
|
82
|
+
return this.refresh();
|
|
83
|
+
}
|
|
73
84
|
|
|
74
85
|
syncScroll() {
|
|
75
86
|
this._syncScroll();
|
|
76
87
|
return this;
|
|
77
88
|
}
|
|
78
89
|
|
|
79
|
-
refresh() {
|
|
80
|
-
if (!this._header || !this._headerTable || !this._body) return this;
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
this.
|
|
84
|
-
|
|
85
|
-
|
|
90
|
+
refresh() {
|
|
91
|
+
if (!this._header || !this._headerTable || !this._body) return this;
|
|
92
|
+
|
|
93
|
+
let widths = this._resolveLayoutWidths();
|
|
94
|
+
const attempts = this._getHeaders().length + 2;
|
|
95
|
+
for (let attempt = 0; attempt < attempts; attempt += 1) {
|
|
96
|
+
this._applyColgroup(this._headerTable, widths);
|
|
97
|
+
this._applyColgroup(this._element, widths);
|
|
98
|
+
const headerChanged = this._captureOverflowingHeaderMinimums();
|
|
99
|
+
const contentChanged = this._syncContentMinimumWidth(widths);
|
|
100
|
+
if (!headerChanged && !contentChanged) break;
|
|
101
|
+
widths = this._resolveLayoutWidths();
|
|
102
|
+
}
|
|
103
|
+
const scrollbar = Math.max(0, this._body.offsetWidth - this._body.clientWidth);
|
|
86
104
|
this._header.style.paddingInlineEnd = `${scrollbar}px`;
|
|
87
105
|
this._header.style.setProperty('--vg-table-sticky-scrollbar-width', `${scrollbar}px`);
|
|
88
106
|
this._header.classList.toggle('vg-table-header--scrollbar', scrollbar > 0);
|
|
@@ -207,6 +225,36 @@ class _stickyHeader {
|
|
|
207
225
|
});
|
|
208
226
|
}
|
|
209
227
|
|
|
228
|
+
_measureIntrinsicColumnMinimums() {
|
|
229
|
+
if (!this._wrapper || !this._head) return [];
|
|
230
|
+
|
|
231
|
+
const probe = this._element.cloneNode(true);
|
|
232
|
+
probe.removeAttribute('data-vg-table');
|
|
233
|
+
probe.removeAttribute('data-vg-table-sticky-header');
|
|
234
|
+
probe.setAttribute('aria-hidden', 'true');
|
|
235
|
+
probe.querySelector(':scope > colgroup[data-vg-table-sticky-colgroup]')?.remove();
|
|
236
|
+
probe.insertBefore(this._head.cloneNode(true), probe.tBodies[0] || null);
|
|
237
|
+
probe.querySelectorAll('thead th').forEach((header) => header.style.setProperty('white-space', 'nowrap', 'important'));
|
|
238
|
+
[
|
|
239
|
+
['position', 'absolute'],
|
|
240
|
+
['inset', '0 auto auto 0'],
|
|
241
|
+
['visibility', 'hidden'],
|
|
242
|
+
['pointer-events', 'none'],
|
|
243
|
+
['width', 'min-content'],
|
|
244
|
+
['min-width', '0'],
|
|
245
|
+
['max-width', 'none'],
|
|
246
|
+
['table-layout', 'auto'],
|
|
247
|
+
].forEach(([property, value]) => probe.style.setProperty(property, value, 'important'));
|
|
248
|
+
|
|
249
|
+
this._wrapper.append(probe);
|
|
250
|
+
try {
|
|
251
|
+
const rows = Array.from(probe.tHead?.rows || []);
|
|
252
|
+
return this._measureRow(rows.at(-1));
|
|
253
|
+
} finally {
|
|
254
|
+
probe.remove();
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
210
258
|
_rememberColumnGeometry(widths) {
|
|
211
259
|
const headers = this._getHeaders();
|
|
212
260
|
const sourceCols = Array.from(this._element.querySelector(':scope > colgroup:not([data-vg-table-sticky-colgroup])')?.children || []);
|
|
@@ -309,6 +357,35 @@ class _stickyHeader {
|
|
|
309
357
|
}
|
|
310
358
|
}
|
|
311
359
|
|
|
360
|
+
_captureOverflowingHeaderMinimums() {
|
|
361
|
+
let changed = false;
|
|
362
|
+
this._getHeaders().forEach((header, index) => {
|
|
363
|
+
const key = this._columnKey(header, index);
|
|
364
|
+
if (this._hasDeclaredWidth(header) || this._hardColumnWidths.has(key)) return;
|
|
365
|
+
|
|
366
|
+
const rendered = header.getBoundingClientRect?.().width || header.clientWidth || 0;
|
|
367
|
+
const required = header.scrollWidth || 0;
|
|
368
|
+
const current = this._columnMinimumWidths.get(key) || 0;
|
|
369
|
+
if (required <= rendered + 1 || required <= current + 1) return;
|
|
370
|
+
|
|
371
|
+
this._columnMinimumWidths.set(key, required);
|
|
372
|
+
changed = true;
|
|
373
|
+
});
|
|
374
|
+
return changed;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
_syncContentMinimumWidth(widths) {
|
|
378
|
+
const total = widths.reduce((sum, width) => sum + width, 0);
|
|
379
|
+
const viewport = this._body?.clientWidth || this._container?.clientWidth || total;
|
|
380
|
+
const previous = this._previousStyles.get(CONTENT_MIN_WIDTH_PROPERTY);
|
|
381
|
+
const required = Math.max(total, this._element?.scrollWidth || 0);
|
|
382
|
+
const next = required > viewport + 1 ? `${Math.ceil(required)}px` : previous;
|
|
383
|
+
const current = this._container.style.getPropertyValue(CONTENT_MIN_WIDTH_PROPERTY);
|
|
384
|
+
if (next) this._container.style.setProperty(CONTENT_MIN_WIDTH_PROPERTY, next);
|
|
385
|
+
else this._container.style.removeProperty(CONTENT_MIN_WIDTH_PROPERTY);
|
|
386
|
+
return current !== (next || '');
|
|
387
|
+
}
|
|
388
|
+
|
|
312
389
|
_getHeaders() {
|
|
313
390
|
const rows = Array.from(this._head?.rows || []);
|
|
314
391
|
return rows.length ? Array.from(rows.at(-1).cells || []) : [];
|
|
@@ -340,9 +417,10 @@ class _stickyHeader {
|
|
|
340
417
|
}
|
|
341
418
|
|
|
342
419
|
_readTableMinimumWidth() {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
420
|
+
const generated = Number.parseFloat(this._container?.style.getPropertyValue(CONTENT_MIN_WIDTH_PROPERTY) || '0');
|
|
421
|
+
if (typeof getComputedStyle !== 'function') return Number.isFinite(generated) ? generated : 0;
|
|
422
|
+
const declared = Number.parseFloat(getComputedStyle(this._element).minWidth || '0');
|
|
423
|
+
return Math.max(Number.isFinite(generated) ? generated : 0, Number.isFinite(declared) ? declared : 0);
|
|
346
424
|
}
|
|
347
425
|
|
|
348
426
|
_syncScroll() {
|
|
@@ -146,11 +146,12 @@ class VGTable extends BaseModule {
|
|
|
146
146
|
if (!this._complex && !this._sorting && this._params.sort.enabled === true && this._params.rowReorder.enabled !== true) {
|
|
147
147
|
this._sorting = new _sorting(this._element, Object.assign({}, this._params.sort, {remote: this._isRemote}), this._stickyHeader?.getHeaderTable());
|
|
148
148
|
this._sorting.init();
|
|
149
|
-
this._element.addEventListener(
|
|
150
|
-
'sortchange.vg.table',
|
|
151
|
-
this._isRemote ? this._boundRemoteSortChange : this._boundLocalSortChange
|
|
152
|
-
);
|
|
153
|
-
}
|
|
149
|
+
this._element.addEventListener(
|
|
150
|
+
'sortchange.vg.table',
|
|
151
|
+
this._isRemote ? this._boundRemoteSortChange : this._boundLocalSortChange
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
this._stickyHeader?.refreshIntrinsicMinimums?.();
|
|
154
155
|
|
|
155
156
|
// Фиксируем настоящие ячейки через native sticky, включая отдельный слой Fixed Header
|
|
156
157
|
if (!this._complex && !this._fixedColumns && this._params.fixedColumns.enabled === true) {
|
|
@@ -1136,7 +1137,7 @@ class VGTable extends BaseModule {
|
|
|
1136
1137
|
|
|
1137
1138
|
_refreshColumnsLayout(structure = false) {
|
|
1138
1139
|
this._sorting?.refresh?.(structure);
|
|
1139
|
-
this._stickyHeader?.
|
|
1140
|
+
this._stickyHeader?.refreshIntrinsicMinimums?.();
|
|
1140
1141
|
this._fixedColumns?.refresh?.();
|
|
1141
1142
|
}
|
|
1142
1143
|
|
|
@@ -1425,11 +1426,11 @@ class VGTable extends BaseModule {
|
|
|
1425
1426
|
_afterRemoteRender(detail = {}) {
|
|
1426
1427
|
if (detail.renderedCount > 0) this._states?.clear();
|
|
1427
1428
|
this._columns?.refresh?.();
|
|
1428
|
-
this._sorting?.refresh?.();
|
|
1429
|
-
this._expandable?.refresh?.();
|
|
1430
|
-
this._rowReorder?.refresh?.();
|
|
1431
|
-
this._stickyHeader?.
|
|
1432
|
-
this._fixedColumns?.refresh?.();
|
|
1429
|
+
this._sorting?.refresh?.();
|
|
1430
|
+
this._expandable?.refresh?.();
|
|
1431
|
+
this._rowReorder?.refresh?.();
|
|
1432
|
+
this._stickyHeader?.refreshIntrinsicMinimums?.();
|
|
1433
|
+
this._fixedColumns?.refresh?.();
|
|
1433
1434
|
}
|
|
1434
1435
|
|
|
1435
1436
|
/**
|
|
@@ -57,9 +57,9 @@
|
|
|
57
57
|
|
|
58
58
|
.vg-table-header__table,
|
|
59
59
|
.vg-table-body > .vg-table {
|
|
60
|
-
width: 100%;
|
|
61
|
-
min-width: 100
|
|
62
|
-
table-layout: fixed;
|
|
60
|
+
width: 100%;
|
|
61
|
+
min-width: max(100%, var(--vg-table-sticky-content-min-width, 0px));
|
|
62
|
+
table-layout: fixed;
|
|
63
63
|
overflow: visible;
|
|
64
64
|
border: 0;
|
|
65
65
|
border-radius: 0;
|