vgapp 1.5.9 → 1.6.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.
- package/app/modules/module-fn.js +1 -1
- package/app/modules/vgnav/js/vgnav.js +242 -14
- package/app/modules/vgnav/scss/vgnav.scss +35 -0
- package/app/modules/vgtable/scss/_fixed-columns.scss +1 -1
- package/app/modules/vgtooltip/js/vgtooltip.js +27 -17
- package/app/modules/vgtooltip/scss/_variables.scss +2 -2
- package/app/modules/vgtooltip/scss/vgtooltip.scss +25 -4
- package/app/utils/js/dom/event.js +25 -23
- 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
package/app/modules/module-fn.js
CHANGED
|
@@ -23,7 +23,7 @@ const getSVG = (name) => {
|
|
|
23
23
|
waiting: '<svg width="72" height="72" viewBox="0 0 72 72" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M51 10.02C55.5248 12.6326 59.2888 16.3816 61.9194 20.8959C64.5501 25.4103 65.9561 30.5334 65.9983 35.7581C66.0405 40.9828 64.7174 46.1279 62.1601 50.6841C59.6027 55.2404 55.8997 59.0497 51.4177 61.735C46.9357 64.4203 41.8301 65.8885 36.6063 65.9942C31.3825 66.1 26.2216 64.8395 21.6347 62.3378C17.0477 59.836 13.1936 56.1796 10.454 51.7306C7.71439 47.2816 6.18423 42.1942 6.015 36.972L6 36L6.015 35.028C6.18301 29.847 7.69064 24.7979 10.3909 20.373C13.0912 15.9481 16.892 12.2984 21.4227 9.77969C25.9534 7.26098 31.0594 5.95923 36.243 6.00136C41.4266 6.04348 46.5108 7.42804 51 10.02ZM36 18C35.2652 18.0001 34.556 18.2699 34.0069 18.7582C33.4578 19.2465 33.107 19.9193 33.021 20.649L33 21V36L33.027 36.393C33.0954 36.9135 33.2992 37.407 33.618 37.824L33.879 38.124L42.879 47.124L43.161 47.37C43.6871 47.7782 44.3341 47.9998 45 47.9998C45.6659 47.9998 46.3129 47.7782 46.839 47.37L47.121 47.121L47.37 46.839C47.7782 46.3129 47.9998 45.6659 47.9998 45C47.9998 44.3341 47.7782 43.6872 47.37 43.161L47.121 42.879L39 34.755V21L38.979 20.649C38.893 19.9193 38.5422 19.2465 37.9931 18.7582C37.444 18.2699 36.7348 18.0001 36 18Z" fill="black"/></svg>',
|
|
24
24
|
warning: '<svg width="72" height="72" viewBox="0 0 72 72" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M36.5 5C44.8543 5 52.8665 8.31874 58.7739 14.2261C64.6813 20.1335 68 28.1457 68 36.5C68 44.8543 64.6813 52.8665 58.7739 58.7739C52.8665 64.6813 44.8543 68 36.5 68C28.1457 68 20.1335 64.6813 14.2261 58.7739C8.31874 52.8665 5 44.8543 5 36.5C5 28.1457 8.31874 20.1335 14.2261 14.2261C20.1335 8.31874 28.1457 5 36.5 5ZM36.5 18.5C35.9287 18.4995 35.3635 18.6181 34.8406 18.8484C34.3178 19.0786 33.8487 19.4154 33.4633 19.8372C33.0779 20.259 32.7848 20.7565 32.6025 21.298C32.4203 21.8395 32.353 22.413 32.405 22.982L34.0475 41.009C34.1112 41.6151 34.397 42.1761 34.8499 42.5839C35.3028 42.9917 35.8906 43.2173 36.5 43.2173C37.1094 43.2173 37.6972 42.9917 38.1501 42.5839C38.603 42.1761 38.8888 41.6151 38.9525 41.009L40.5905 22.982C40.6424 22.4134 40.5753 21.8403 40.3933 21.2991C40.2114 20.7579 39.9186 20.2606 39.5337 19.8389C39.1488 19.4171 38.6803 19.0803 38.1579 18.8498C37.6356 18.6192 37.0709 18.5001 36.5 18.5ZM36.5 54.5C37.4548 54.5 38.3705 54.1207 39.0456 53.4456C39.7207 52.7705 40.1 51.8548 40.1 50.9C40.1 49.9452 39.7207 49.0295 39.0456 48.3544C38.3705 47.6793 37.4548 47.3 36.5 47.3C35.5452 47.3 34.6295 47.6793 33.9544 48.3544C33.2793 49.0295 32.9 49.9452 32.9 50.9C32.9 51.8548 33.2793 52.7705 33.9544 53.4456C34.6295 54.1207 35.5452 54.5 36.5 54.5Z" fill="#000000"/></svg>',
|
|
25
25
|
info: '<svg width="72" height="72" viewBox="0 0 72 72" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M36 4.5C18.6047 4.5 4.5 18.6047 4.5 36C4.5 53.3953 18.6047 67.5 36 67.5C53.3953 67.5 67.5 53.3953 67.5 36C67.5 18.6047 53.3953 4.5 36 4.5ZM33.75 20.8125C33.75 20.5031 34.0031 20.25 34.3125 20.25H37.6875C37.9969 20.25 38.25 20.5031 38.25 20.8125V39.9375C38.25 40.2469 37.9969 40.5 37.6875 40.5H34.3125C34.0031 40.5 33.75 40.2469 33.75 39.9375V20.8125ZM36 51.75C35.1168 51.732 34.2759 51.3685 33.6577 50.7375C33.0395 50.1065 32.6932 49.2584 32.6932 48.375C32.6932 47.4916 33.0395 46.6435 33.6577 46.0125C34.2759 45.3815 35.1168 45.018 36 45C36.8832 45.018 37.7241 45.3815 38.3423 46.0125C38.9605 46.6435 39.3068 47.4916 39.3068 48.375C39.3068 49.2584 38.9605 50.1065 38.3423 50.7375C37.7241 51.3685 36.8832 51.732 36 51.75Z" fill="#000000"/></svg>',
|
|
26
|
-
dots: '<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M10 17C11.1046 17 12 16.1046 12 15C12 13.8954 11.1046 13 10 13C8.89543 13 8 13.8954 8 15C8 16.1046 8.89543 17 10 17Z" fill="
|
|
26
|
+
dots: '<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M10 17C11.1046 17 12 16.1046 12 15C12 13.8954 11.1046 13 10 13C8.89543 13 8 13.8954 8 15C8 16.1046 8.89543 17 10 17Z" fill="currentColor"/><path d="M10 12C11.1046 12 12 11.1046 12 10C12 8.89543 11.1046 8 10 8C8.89543 8 8 8.89543 8 10C8 11.1046 8.89543 12 10 12Z" fill="currentColor"/><path d="M10 7C11.1046 7 12 6.10457 12 5C12 3.89543 11.1046 3 10 3C8.89543 3 8 3.89543 8 5C8 6.10457 8.89543 7 10 7Z" fill="currentColor"/></svg>',
|
|
27
27
|
remove: '<svg class="vg-icon-remove" width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M7.05 5.636 12 10.586l4.95-4.95 1.414 1.414-4.95 4.95 4.95 4.95-1.414 1.414L12 13.414l-4.95 4.95-1.414-1.414 4.95-4.95-4.95-4.95L7.05 5.636Z" fill="currentColor"/></svg>',
|
|
28
28
|
cross: '<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M15.3149 0.340332C15.4478 0.20752 15.6027 0.118978 15.7798 0.074707C15.9569 0.0249023 16.134 0.0249023 16.311 0.074707C16.4881 0.118978 16.6431 0.20752 16.7759 0.340332C16.9142 0.473145 17.0055 0.630859 17.0498 0.813477C17.0941 0.99056 17.0941 1.16764 17.0498 1.34473C17.0055 1.52181 16.917 1.67676 16.7842 1.80957L1.80127 16.8008C1.67399 16.9281 1.52181 17.0111 1.34473 17.0498C1.16764 17.0941 0.987793 17.0941 0.805176 17.0498C0.628092 17.0111 0.470378 16.9253 0.332031 16.7925C0.199219 16.6597 0.110677 16.502 0.0664062 16.3193C0.0221354 16.1423 0.0221354 15.9652 0.0664062 15.7881C0.110677 15.611 0.196452 15.4588 0.32373 15.3315L15.3149 0.340332ZM16.7842 15.3232C16.917 15.4561 17.0028 15.6082 17.0415 15.7798C17.0858 15.9569 17.0858 16.134 17.0415 16.311C17.0028 16.4937 16.9142 16.6541 16.7759 16.7925C16.6431 16.9253 16.4881 17.0138 16.311 17.0581C16.134 17.1024 15.9569 17.1024 15.7798 17.0581C15.6027 17.0138 15.4478 16.9253 15.3149 16.7925L0.32373 1.80127C0.201986 1.67952 0.116211 1.53011 0.0664062 1.35303C0.0221354 1.17594 0.0221354 0.996094 0.0664062 0.813477C0.116211 0.630859 0.204753 0.473145 0.332031 0.340332C0.464844 0.20752 0.622559 0.118978 0.805176 0.074707C0.987793 0.0304362 1.16488 0.0304362 1.33643 0.074707C1.51351 0.118978 1.66846 0.204753 1.80127 0.332031L16.7842 15.3232Z" fill="#000"/></svg>',
|
|
29
29
|
'eye-open': '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path d="M288 80c-65.2 0-118.8 29.6-159.9 67.7C89.6 183.5 63 226 49.4 256c13.6 30 40.2 72.5 78.6 108.3C169.2 402.4 222.8 432 288 432s118.8-29.6 159.9-67.7C486.4 328.5 513 286 526.6 256c-13.6-30-40.2-72.5-78.6-108.3C406.8 109.6 353.2 80 288 80zM95.4 112.6C142.5 68.8 207.2 32 288 32s145.5 36.8 192.6 80.6c46.8 43.5 78.1 95.4 93 131.1c3.3 7.9 3.3 16.7 0 24.6c-14.9 35.7-46.2 87.7-93 131.1C433.5 443.2 368.8 480 288 480s-145.5-36.8-192.6-80.6C48.6 356 17.3 304 2.5 268.3c-3.3-7.9-3.3-16.7 0-24.6C17.3 208 48.6 156 95.4 112.6zM288 336c44.2 0 80-35.8 80-80s-35.8-80-80-80c-.7 0-1.3 0-2 0c1.3 5.1 2 10.5 2 16c0 35.3-28.7 64-64 64c-5.5 0-10.9-.7-16-2c0 .7 0 1.3 0 2c0 44.2 35.8 80 80 80zm0-208a128 128 0 1 1 0 256 128 128 0 1 1 0-256z"/></svg>',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Описание: адаптивная навигация VGNav с выпадающими пунктами и гамбургером.
|
|
3
|
-
* Возможности: click/hover, вложенные меню, позиционирование, события и интеграция с VGSidebar.
|
|
3
|
+
* Возможности: click/hover, overflow первого уровня, вложенные меню, позиционирование, события и интеграция с VGSidebar.
|
|
4
4
|
*/
|
|
5
5
|
import BaseModule from "../../base-module";
|
|
6
6
|
import Selectors from "../../../utils/js/dom/selectors";
|
|
@@ -15,7 +15,8 @@ import {
|
|
|
15
15
|
} from "../../../utils/js/functions";
|
|
16
16
|
import EventHandler from "../../../utils/js/dom/event";
|
|
17
17
|
import {Manipulator} from "../../../utils/js/dom/manipulator";
|
|
18
|
-
import Placement from "../../../utils/js/components/placement";
|
|
18
|
+
import Placement from "../../../utils/js/components/placement";
|
|
19
|
+
import {getSVG} from "../../module-fn";
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* Constants
|
|
@@ -60,8 +61,22 @@ class VGNav extends BaseModule {
|
|
|
60
61
|
placement: 'horizontal',
|
|
61
62
|
// Включает открытие выпадающих пунктов при наведении на десктопе.
|
|
62
63
|
hover: true,
|
|
63
|
-
// Включает ограничение высоты и overflow для списка внутри выпадающего меню.
|
|
64
|
-
dropListScroll: true,
|
|
64
|
+
// Включает ограничение высоты и overflow для списка внутри выпадающего меню.
|
|
65
|
+
dropListScroll: true,
|
|
66
|
+
// Переносит лишние пункты первого уровня горизонтального меню в dropdown.
|
|
67
|
+
overflow: {
|
|
68
|
+
enable: false,
|
|
69
|
+
// Максимум видимых исходных пунктов; 0 оставляет только ограничение по ширине.
|
|
70
|
+
count: 0,
|
|
71
|
+
// Элементы, которые нельзя переносить (megamenu сохраняет геометрию первого уровня).
|
|
72
|
+
keep: '.dropdown-mega, [data-vg-nav-overflow="keep"]',
|
|
73
|
+
trigger: {
|
|
74
|
+
icon: 'dots',
|
|
75
|
+
body: null,
|
|
76
|
+
label: '',
|
|
77
|
+
ariaLabel: 'Другие разделы'
|
|
78
|
+
}
|
|
79
|
+
},
|
|
65
80
|
// Настройки плавного переключения между соседними пунктами первого уровня.
|
|
66
81
|
hoversmoothfirstlevel: {
|
|
67
82
|
// Включает режим плавного перехода без мгновенного закрытия соседнего дропа.
|
|
@@ -105,8 +120,11 @@ class VGNav extends BaseModule {
|
|
|
105
120
|
hamburgerAlways: 'vg-nav-hamburger-always',
|
|
106
121
|
hamburger: 'vg-nav-hamburger',
|
|
107
122
|
container: 'vg-nav-container',
|
|
108
|
-
wrapper: 'vg-nav-wrapper',
|
|
109
|
-
dropListScroll: 'vg-nav-drop-list-scroll',
|
|
123
|
+
wrapper: 'vg-nav-wrapper',
|
|
124
|
+
dropListScroll: 'vg-nav-drop-list-scroll',
|
|
125
|
+
overflowEnabled: 'vg-nav-overflow-enabled',
|
|
126
|
+
overflow: 'vg-nav-overflow',
|
|
127
|
+
overflowList: 'vg-nav-overflow-list',
|
|
110
128
|
active: 'vg-nav-active',
|
|
111
129
|
expand: 'vg-nav-expand',
|
|
112
130
|
cloned: 'vg-nav-cloned',
|
|
@@ -131,8 +149,16 @@ class VGNav extends BaseModule {
|
|
|
131
149
|
this._openDrops = new Map();
|
|
132
150
|
this._pointerPosition = null;
|
|
133
151
|
this._smoothSwitch = null;
|
|
134
|
-
this._handleScroll = this._handleScroll.bind(this);
|
|
135
|
-
this._handleResize = this._handleResize.bind(this);
|
|
152
|
+
this._handleScroll = this._handleScroll.bind(this);
|
|
153
|
+
this._handleResize = this._handleResize.bind(this);
|
|
154
|
+
this._handleOverflowResize = this._handleOverflowResize.bind(this);
|
|
155
|
+
this._overflowTrigger = null;
|
|
156
|
+
this._overflowList = null;
|
|
157
|
+
this._overflowItems = [];
|
|
158
|
+
this._overflowAnchors = new Map();
|
|
159
|
+
this._overflowObserver = null;
|
|
160
|
+
this._overflowFrame = null;
|
|
161
|
+
this._overflowWindowFallback = false;
|
|
136
162
|
}
|
|
137
163
|
|
|
138
164
|
static get NAME() {
|
|
@@ -162,7 +188,8 @@ class VGNav extends BaseModule {
|
|
|
162
188
|
// Вешаем основные классы
|
|
163
189
|
this._element.classList.add(classes.container);
|
|
164
190
|
this._element.classList.add('vg-nav-' + params.placement);
|
|
165
|
-
this._element.classList.toggle(classes.dropListScroll, !!params.dropListScroll);
|
|
191
|
+
this._element.classList.toggle(classes.dropListScroll, !!params.dropListScroll);
|
|
192
|
+
this._setupOverflow();
|
|
166
193
|
|
|
167
194
|
if (!params.hamburger.always) {
|
|
168
195
|
if (!params.breakpoint) {
|
|
@@ -202,7 +229,7 @@ class VGNav extends BaseModule {
|
|
|
202
229
|
}
|
|
203
230
|
|
|
204
231
|
// Устанавливаем указатель дропа
|
|
205
|
-
if (params.toggle) {
|
|
232
|
+
if (params.toggle) {
|
|
206
233
|
let $dropdown_a = [...Selectors.findAll('.dropdown > a', this._element)],
|
|
207
234
|
toggle = '<span class="toggle">' + params.toggle + '</span>';
|
|
208
235
|
|
|
@@ -213,10 +240,12 @@ class VGNav extends BaseModule {
|
|
|
213
240
|
elem.insertAdjacentHTML('beforeend', toggle);
|
|
214
241
|
}
|
|
215
242
|
});
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
this.refresh();
|
|
247
|
+
|
|
248
|
+
if ('afterInit' in this._params.callbacks) {
|
|
220
249
|
execute(this._params.callbacks.afterInit, [this]);
|
|
221
250
|
}
|
|
222
251
|
}
|
|
@@ -421,6 +450,205 @@ class VGNav extends BaseModule {
|
|
|
421
450
|
window.setTimeout(callback, duration);
|
|
422
451
|
}
|
|
423
452
|
|
|
453
|
+
/**
|
|
454
|
+
* Пересчитывает пункты первого уровня, перенесённые в overflow-dropdown.
|
|
455
|
+
* Полезно вызывать после динамического изменения состава или текста меню.
|
|
456
|
+
*/
|
|
457
|
+
refresh() {
|
|
458
|
+
if (!this._isOverflowEnabled()) return;
|
|
459
|
+
this._collectOverflowItems();
|
|
460
|
+
this._redistributeOverflowItems();
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
_isOverflowEnabled() {
|
|
464
|
+
return !!this._params.overflow?.enable && this._params.placement === 'horizontal';
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
_setupOverflow() {
|
|
468
|
+
if (!this._isOverflowEnabled() || this._overflowTrigger) return;
|
|
469
|
+
|
|
470
|
+
this._element.classList.add(this._classes.overflowEnabled);
|
|
471
|
+
const triggerParams = this._params.overflow.trigger || {};
|
|
472
|
+
const item = document.createElement('li');
|
|
473
|
+
item.classList.add('dropdown', 'dots', this._classes.overflow);
|
|
474
|
+
item.hidden = true;
|
|
475
|
+
|
|
476
|
+
const link = document.createElement('a');
|
|
477
|
+
link.href = '#';
|
|
478
|
+
link.setAttribute('aria-expanded', 'false');
|
|
479
|
+
link.setAttribute('aria-label', triggerParams.ariaLabel || 'Другие разделы');
|
|
480
|
+
|
|
481
|
+
const icon = document.createElement('span');
|
|
482
|
+
icon.classList.add(this._classes.overflow + '-icon');
|
|
483
|
+
icon.setAttribute('aria-hidden', 'true');
|
|
484
|
+
icon.innerHTML = triggerParams.body !== null
|
|
485
|
+
? triggerParams.body
|
|
486
|
+
: (getSVG(triggerParams.icon || 'dots') || '');
|
|
487
|
+
link.append(icon);
|
|
488
|
+
|
|
489
|
+
if (triggerParams.label) {
|
|
490
|
+
const label = document.createElement('span');
|
|
491
|
+
label.classList.add(this._classes.overflow + '-label');
|
|
492
|
+
label.textContent = triggerParams.label;
|
|
493
|
+
link.append(label);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
const content = document.createElement('div');
|
|
497
|
+
content.classList.add('dropdown-content');
|
|
498
|
+
const list = document.createElement('ul');
|
|
499
|
+
list.classList.add('vg-nav-drop-list', this._classes.overflowList);
|
|
500
|
+
content.append(list);
|
|
501
|
+
item.append(link, content);
|
|
502
|
+
this.navigation.append(item);
|
|
503
|
+
|
|
504
|
+
this._overflowTrigger = item;
|
|
505
|
+
this._overflowList = list;
|
|
506
|
+
this._collectOverflowItems();
|
|
507
|
+
this._startOverflowObserver();
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
_collectOverflowItems() {
|
|
511
|
+
if (!this.navigation || !this._overflowTrigger) return;
|
|
512
|
+
|
|
513
|
+
[...this.navigation.children].forEach((item) => {
|
|
514
|
+
if (item === this._overflowTrigger || this._overflowAnchors.has(item)) return;
|
|
515
|
+
const anchor = document.createComment('vg-nav-overflow-item');
|
|
516
|
+
this.navigation.insertBefore(anchor, item);
|
|
517
|
+
this._overflowAnchors.set(item, anchor);
|
|
518
|
+
this._overflowItems.push(item);
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
_restoreOverflowItems(removeAnchors = false) {
|
|
523
|
+
this._overflowItems.forEach((item) => {
|
|
524
|
+
const anchor = this._overflowAnchors.get(item);
|
|
525
|
+
if (!anchor?.parentNode) return;
|
|
526
|
+
if (removeAnchors) {
|
|
527
|
+
anchor.replaceWith(item);
|
|
528
|
+
} else {
|
|
529
|
+
anchor.after(item);
|
|
530
|
+
}
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
if (removeAnchors) this._overflowAnchors.clear();
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
_redistributeOverflowItems() {
|
|
537
|
+
if (!this.navigation || !this._overflowTrigger || !this._overflowList) return;
|
|
538
|
+
|
|
539
|
+
this._closeOverflowDrops();
|
|
540
|
+
this._restoreOverflowItems();
|
|
541
|
+
this._overflowTrigger.hidden = true;
|
|
542
|
+
|
|
543
|
+
if (!this._isOverflowMeasurable()) return;
|
|
544
|
+
|
|
545
|
+
const moved = new Set();
|
|
546
|
+
const movable = this._overflowItems.filter((item) => !this._isOverflowKept(item));
|
|
547
|
+
const count = Math.max(0, Number.parseInt(this._params.overflow.count, 10) || 0);
|
|
548
|
+
let visibleCount = this._overflowItems.length;
|
|
549
|
+
|
|
550
|
+
if (count > 0) {
|
|
551
|
+
for (let index = movable.length - 1; index >= 0 && visibleCount > count; index--) {
|
|
552
|
+
moved.add(movable[index]);
|
|
553
|
+
this._overflowList.prepend(movable[index]);
|
|
554
|
+
visibleCount--;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
if (moved.size || !this._overflowFits()) {
|
|
559
|
+
this._overflowTrigger.hidden = false;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
for (let index = movable.length - 1; index >= 0 && !this._overflowFits(); index--) {
|
|
563
|
+
const item = movable[index];
|
|
564
|
+
if (moved.has(item)) continue;
|
|
565
|
+
moved.add(item);
|
|
566
|
+
this._overflowList.prepend(item);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
this._overflowItems.forEach((item) => {
|
|
570
|
+
if (moved.has(item)) this._overflowList.append(item);
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
this._overflowTrigger.hidden = moved.size === 0;
|
|
574
|
+
this._element.classList.toggle(this._classes.overflow + '-active', moved.size > 0);
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
_isOverflowKept(item) {
|
|
578
|
+
const selector = String(this._params.overflow.keep || '').trim();
|
|
579
|
+
return !!selector && item.matches(selector);
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
_isOverflowMeasurable() {
|
|
583
|
+
if (!this._element.isConnected) return false;
|
|
584
|
+
if (this.navigation.getClientRects().length === 0) return false;
|
|
585
|
+
return this.navigation.clientWidth > 0 || this.navigation.getBoundingClientRect().width > 0;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
_overflowFits() {
|
|
589
|
+
const width = this.navigation.clientWidth || this.navigation.getBoundingClientRect().width;
|
|
590
|
+
if (!width) return true;
|
|
591
|
+
|
|
592
|
+
const style = window.getComputedStyle(this.navigation);
|
|
593
|
+
const gap = Number.parseFloat(style.columnGap) || 0;
|
|
594
|
+
const children = [...this.navigation.children].filter((item) => !item.hidden);
|
|
595
|
+
const used = children.reduce((sum, item) => {
|
|
596
|
+
const itemStyle = window.getComputedStyle(item);
|
|
597
|
+
return sum + item.getBoundingClientRect().width
|
|
598
|
+
+ (Number.parseFloat(itemStyle.marginLeft) || 0)
|
|
599
|
+
+ (Number.parseFloat(itemStyle.marginRight) || 0);
|
|
600
|
+
}, 0) + Math.max(0, children.length - 1) * gap;
|
|
601
|
+
|
|
602
|
+
return used <= width + 0.5;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
_closeOverflowDrops() {
|
|
606
|
+
[...this.navigation.querySelectorAll('.dropdown.active')].forEach((item) => {
|
|
607
|
+
this.hide({relatedTarget: item});
|
|
608
|
+
});
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
_startOverflowObserver() {
|
|
612
|
+
if (typeof ResizeObserver !== 'undefined') {
|
|
613
|
+
this._overflowObserver = new ResizeObserver(this._handleOverflowResize);
|
|
614
|
+
this._overflowObserver.observe(this.navigation);
|
|
615
|
+
this._overflowObserver.observe(this._element);
|
|
616
|
+
} else {
|
|
617
|
+
window.addEventListener('resize', this._handleOverflowResize);
|
|
618
|
+
this._overflowWindowFallback = true;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
if (document.fonts?.ready) {
|
|
622
|
+
document.fonts.ready.then(() => {
|
|
623
|
+
if (this._element) this._handleOverflowResize();
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
_handleOverflowResize() {
|
|
629
|
+
if (this._overflowFrame !== null) return;
|
|
630
|
+
const schedule = typeof window.requestAnimationFrame === 'function'
|
|
631
|
+
? window.requestAnimationFrame.bind(window)
|
|
632
|
+
: (callback) => window.setTimeout(callback, 0);
|
|
633
|
+
|
|
634
|
+
this._overflowFrame = schedule(() => {
|
|
635
|
+
this._overflowFrame = null;
|
|
636
|
+
this.refresh();
|
|
637
|
+
});
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
dispose() {
|
|
641
|
+
if (this._overflowObserver) this._overflowObserver.disconnect();
|
|
642
|
+
if (this._overflowWindowFallback) window.removeEventListener('resize', this._handleOverflowResize);
|
|
643
|
+
if (this._overflowFrame !== null && typeof window.cancelAnimationFrame === 'function') {
|
|
644
|
+
window.cancelAnimationFrame(this._overflowFrame);
|
|
645
|
+
}
|
|
646
|
+
this._restoreOverflowItems(true);
|
|
647
|
+
this._overflowTrigger?.remove();
|
|
648
|
+
this._element.classList.remove(this._classes.overflowEnabled, this._classes.overflow + '-active');
|
|
649
|
+
super.dispose();
|
|
650
|
+
}
|
|
651
|
+
|
|
424
652
|
_startSmoothSwitch(currentDrop, previousDrop, dropContent) {
|
|
425
653
|
const staleSwitch = this._smoothSwitch;
|
|
426
654
|
const transfer = { currentDrop, previousDrop };
|
|
@@ -150,6 +150,41 @@
|
|
|
150
150
|
}
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
+
&.vg-nav-overflow-enabled.vg-nav-horizontal {
|
|
154
|
+
> .vg-nav-wrapper {
|
|
155
|
+
width: 100%;
|
|
156
|
+
min-width: 0;
|
|
157
|
+
flex-wrap: nowrap;
|
|
158
|
+
|
|
159
|
+
> li {
|
|
160
|
+
flex: 0 0 auto;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.vg-nav-overflow {
|
|
165
|
+
> a {
|
|
166
|
+
align-items: center;
|
|
167
|
+
justify-content: center;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
&-icon {
|
|
171
|
+
display: inline-flex;
|
|
172
|
+
align-items: center;
|
|
173
|
+
justify-content: center;
|
|
174
|
+
line-height: 1;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
&-label:not(:first-child) {
|
|
178
|
+
margin-left: .375rem;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
> .dropdown-content > .vg-nav-overflow-list {
|
|
182
|
+
max-height: none;
|
|
183
|
+
overflow: visible;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
153
188
|
/** set placement **/
|
|
154
189
|
@include placement.placement();
|
|
155
190
|
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
background-color: var(--vg-table-fixed-cell-bg);
|
|
60
60
|
background-image: none;
|
|
61
61
|
box-shadow: inset 0 0 0 100vmax transparent;
|
|
62
|
-
transition:
|
|
62
|
+
transition: var(--vg-table-transition);
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
.vg-table-striped tbody tr:nth-child(even) > [data-vg-table-fixed-side] {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Описание: всплывающие подсказки и информационные popover VGApp.
|
|
3
|
-
* Возможности: Data API,
|
|
3
|
+
* Возможности: Data API, подавление нативного title, позиционирование со стрелкой без зазоров и очистка при удалении триггера.
|
|
4
4
|
*/
|
|
5
5
|
import BaseModule from "../../base-module";
|
|
6
6
|
import {isDisabled, makeRandomString, mergeDeepObject} from "../../../utils/js/functions";
|
|
@@ -94,7 +94,8 @@ class VGTooltip extends BaseModule {
|
|
|
94
94
|
this._isHiding = false;
|
|
95
95
|
this._showTimeout = null;
|
|
96
96
|
this._hideTimeout = null;
|
|
97
|
-
this._triggerObserver = null;
|
|
97
|
+
this._triggerObserver = null;
|
|
98
|
+
this._titleSuppressed = false;
|
|
98
99
|
|
|
99
100
|
this._fixTitle();
|
|
100
101
|
|
|
@@ -122,10 +123,15 @@ class VGTooltip extends BaseModule {
|
|
|
122
123
|
return this._isShown() ? this.hide() : this.show(relatedTarget);
|
|
123
124
|
}
|
|
124
125
|
|
|
125
|
-
show(relatedTarget) {
|
|
126
|
-
if (
|
|
127
|
-
|
|
128
|
-
this.
|
|
126
|
+
show(relatedTarget) {
|
|
127
|
+
if (!this._element || isDisabled(this._element)) return;
|
|
128
|
+
|
|
129
|
+
this._fixTitle();
|
|
130
|
+
this._clearTimeouts();
|
|
131
|
+
if (this._isShown()) {
|
|
132
|
+
if (!this._isHiding) this._observeTrigger();
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
129
135
|
|
|
130
136
|
this._showTimeout = setTimeout(() => {
|
|
131
137
|
this._showTimeout = null;
|
|
@@ -226,7 +232,9 @@ class VGTooltip extends BaseModule {
|
|
|
226
232
|
|
|
227
233
|
if (Object.prototype.hasOwnProperty.call(this._element.dataset, 'vgOriginalTitle')) {
|
|
228
234
|
this._element.setAttribute('title', this._element.dataset.vgOriginalTitle);
|
|
229
|
-
this._element.removeAttribute('data-vg-original-title');
|
|
235
|
+
this._element.removeAttribute('data-vg-original-title');
|
|
236
|
+
} else {
|
|
237
|
+
this._element.removeAttribute('title');
|
|
230
238
|
}
|
|
231
239
|
}
|
|
232
240
|
|
|
@@ -319,10 +327,12 @@ class VGTooltip extends BaseModule {
|
|
|
319
327
|
_fixTitle() {
|
|
320
328
|
const title = this._element.getAttribute('title');
|
|
321
329
|
|
|
322
|
-
if (title
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
330
|
+
if (title !== null && (title !== '' || !this._titleSuppressed)) {
|
|
331
|
+
this._element.setAttribute('data-vg-original-title', title);
|
|
332
|
+
}
|
|
333
|
+
// Пустой title также блокирует нативную подсказку, унаследованную от предка.
|
|
334
|
+
this._element.setAttribute('title', '');
|
|
335
|
+
this._titleSuppressed = true;
|
|
326
336
|
}
|
|
327
337
|
|
|
328
338
|
_setPlacement() {
|
|
@@ -378,12 +388,12 @@ class VGTooltip extends BaseModule {
|
|
|
378
388
|
);
|
|
379
389
|
|
|
380
390
|
arrow.style.left = `${arrowLeft}px`;
|
|
381
|
-
arrow.style.transform = 'translateX(-50%)
|
|
391
|
+
arrow.style.transform = 'translateX(-50%)';
|
|
382
392
|
|
|
383
393
|
if (placement.startsWith('top')) {
|
|
384
|
-
arrow.style.bottom = '-
|
|
394
|
+
arrow.style.bottom = 'calc(var(--vg-tooltip-arrow-height) / -2 + 1px)';
|
|
385
395
|
} else {
|
|
386
|
-
arrow.style.top = '-
|
|
396
|
+
arrow.style.top = 'calc(var(--vg-tooltip-arrow-height) / -2 + 1px)';
|
|
387
397
|
}
|
|
388
398
|
}
|
|
389
399
|
|
|
@@ -396,12 +406,12 @@ class VGTooltip extends BaseModule {
|
|
|
396
406
|
);
|
|
397
407
|
|
|
398
408
|
arrow.style.top = `${arrowTop}px`;
|
|
399
|
-
arrow.style.transform = 'translateY(-50%)
|
|
409
|
+
arrow.style.transform = 'translateY(-50%)';
|
|
400
410
|
|
|
401
411
|
if (placement.startsWith('left')) {
|
|
402
|
-
arrow.style.right = '-
|
|
412
|
+
arrow.style.right = 'calc(var(--vg-tooltip-arrow-width) / -2 + 1px)';
|
|
403
413
|
} else {
|
|
404
|
-
arrow.style.left = '-
|
|
414
|
+
arrow.style.left = 'calc(var(--vg-tooltip-arrow-width) / -2 + 1px)';
|
|
405
415
|
}
|
|
406
416
|
}
|
|
407
417
|
}
|
|
@@ -11,7 +11,7 @@ $tooltip-map: (
|
|
|
11
11
|
border-radius: 6px,
|
|
12
12
|
box-shadow: 0 6px 20px var(--vg-shadow-soft-color, rgba(0, 0, 0, .18)),
|
|
13
13
|
word-break: break-word,
|
|
14
|
-
arrow-width:
|
|
15
|
-
arrow-height:
|
|
14
|
+
arrow-width: 10px,
|
|
15
|
+
arrow-height: 10px,
|
|
16
16
|
border-color: var(--vg-border-color, #{vg.$border-color}),
|
|
17
17
|
) !default;
|
|
@@ -12,7 +12,9 @@
|
|
|
12
12
|
|
|
13
13
|
.vg-tooltip {
|
|
14
14
|
@include vg.mix-vars('tooltip', vars.$tooltip-map);
|
|
15
|
-
position: absolute;
|
|
15
|
+
position: absolute;
|
|
16
|
+
// Координатами управляет Placement; общие data-vg-placement правила не должны задавать противоположный край.
|
|
17
|
+
inset: auto;
|
|
16
18
|
z-index: var(--vg-tooltip-zindex);
|
|
17
19
|
pointer-events: none;
|
|
18
20
|
opacity: 0;
|
|
@@ -42,9 +44,28 @@
|
|
|
42
44
|
position: absolute;
|
|
43
45
|
width: var(--vg-tooltip-arrow-width);
|
|
44
46
|
height: var(--vg-tooltip-arrow-height);
|
|
45
|
-
background: var(--vg-tooltip-background, #222);
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
background: var(--vg-tooltip-background, #222);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
&[data-vg-placement^="top"] &-arrow {
|
|
51
|
+
height: calc(var(--vg-tooltip-arrow-height) / 2);
|
|
52
|
+
clip-path: polygon(0 0, 100% 0, 50% 100%);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
&[data-vg-placement^="bottom"] &-arrow {
|
|
56
|
+
height: calc(var(--vg-tooltip-arrow-height) / 2);
|
|
57
|
+
clip-path: polygon(50% 0, 100% 100%, 0 100%);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
&[data-vg-placement^="left"] &-arrow {
|
|
61
|
+
width: calc(var(--vg-tooltip-arrow-width) / 2);
|
|
62
|
+
clip-path: polygon(0 0, 100% 50%, 0 100%);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
&[data-vg-placement^="right"] &-arrow {
|
|
66
|
+
width: calc(var(--vg-tooltip-arrow-width) / 2);
|
|
67
|
+
clip-path: polygon(100% 0, 100% 100%, 0 50%);
|
|
68
|
+
}
|
|
48
69
|
|
|
49
70
|
&-popover {
|
|
50
71
|
.vg-tooltip-inner {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* Описание: управление DOM-событиями VGApp.
|
|
3
|
+
* Возможности: делегирование, пространства имён, одноразовые подписки и границы mouseenter/mouseleave.
|
|
2
4
|
* --------------------------------------------------------------------------
|
|
3
5
|
* Bootstrap event.js (рефакторинг)
|
|
4
6
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
|
@@ -79,9 +81,10 @@ const getElementEvents = (element) => {
|
|
|
79
81
|
* @param {boolean} isOneOff
|
|
80
82
|
* @returns {Function}
|
|
81
83
|
*/
|
|
82
|
-
const createHandler = (element, fn, isOneOff) => {
|
|
83
|
-
const handler = function (event) {
|
|
84
|
-
hydrateObj(event, { delegateTarget: element });
|
|
84
|
+
const createHandler = (element, fn, isOneOff, checkRelatedTarget) => {
|
|
85
|
+
const handler = function (event) {
|
|
86
|
+
hydrateObj(event, { delegateTarget: element });
|
|
87
|
+
if (checkRelatedTarget && isRelatedTargetInside(event)) return;
|
|
85
88
|
|
|
86
89
|
if (isOneOff) {
|
|
87
90
|
EventHandler.off(element, event.type, fn);
|
|
@@ -106,13 +109,14 @@ const createHandler = (element, fn, isOneOff) => {
|
|
|
106
109
|
* @param {boolean} isOneOff
|
|
107
110
|
* @returns {Function}
|
|
108
111
|
*/
|
|
109
|
-
const createDelegatedHandler = (element, selector, fn, isOneOff) => {
|
|
112
|
+
const createDelegatedHandler = (element, selector, fn, isOneOff, checkRelatedTarget) => {
|
|
110
113
|
const handler = function (event) {
|
|
111
114
|
const candidates = Array.from(element.querySelectorAll(selector));
|
|
112
115
|
for (let target = event.target; target && target !== element; target = target.parentNode) {
|
|
113
116
|
if (!candidates.includes(target)) continue;
|
|
114
117
|
|
|
115
|
-
hydrateObj(event, { delegateTarget: target });
|
|
118
|
+
hydrateObj(event, { delegateTarget: target });
|
|
119
|
+
if (checkRelatedTarget && isRelatedTargetInside(event)) return;
|
|
116
120
|
|
|
117
121
|
if (isOneOff) {
|
|
118
122
|
EventHandler.off(element, event.type, selector, fn);
|
|
@@ -131,19 +135,16 @@ const createDelegatedHandler = (element, selector, fn, isOneOff) => {
|
|
|
131
135
|
};
|
|
132
136
|
|
|
133
137
|
/**
|
|
134
|
-
*
|
|
135
|
-
* @param {
|
|
136
|
-
* @returns {
|
|
137
|
-
*/
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
return fn.call(this, event);
|
|
145
|
-
}
|
|
146
|
-
};
|
|
138
|
+
* Проверяет переход внутри одного триггера mouseenter/mouseleave.
|
|
139
|
+
* @param {Event} event
|
|
140
|
+
* @returns {boolean}
|
|
141
|
+
*/
|
|
142
|
+
const isRelatedTargetInside = (event) => {
|
|
143
|
+
const relatedTarget = event.relatedTarget;
|
|
144
|
+
return !!relatedTarget && (
|
|
145
|
+
relatedTarget === event.delegateTarget ||
|
|
146
|
+
(relatedTarget.nodeType && event.delegateTarget.contains(relatedTarget))
|
|
147
|
+
);
|
|
147
148
|
};
|
|
148
149
|
|
|
149
150
|
/**
|
|
@@ -193,9 +194,10 @@ const addHandler = (element, originalTypeEvent, handler, delegationFunction, one
|
|
|
193
194
|
return;
|
|
194
195
|
}
|
|
195
196
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
197
|
+
const checkRelatedTarget = Boolean(customEvents[originalTypeEvent.replace(STRIP_NAME_REGEX, '')]);
|
|
198
|
+
let fn = isDelegated
|
|
199
|
+
? createDelegatedHandler(element, handler, callable, oneOff, checkRelatedTarget)
|
|
200
|
+
: createHandler(element, callable, oneOff, checkRelatedTarget);
|
|
199
201
|
|
|
200
202
|
const uid = makeEventUid(fn, originalTypeEvent.replace(NAMESPACE_REGEX, ''));
|
|
201
203
|
fn.uidEvent = uid;
|
|
@@ -362,4 +364,4 @@ const EventHandler = {
|
|
|
362
364
|
}
|
|
363
365
|
};
|
|
364
366
|
|
|
365
|
-
export default EventHandler;
|
|
367
|
+
export default EventHandler;
|