vgapp 0.4.1 → 0.4.3
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 +5 -0
- package/app/modules/base-module.js +7 -0
- package/app/modules/vgcollapse/js/vgcollapse.js +1 -0
- package/app/modules/vgdropdown/js/vgdropdown.js +1 -0
- package/app/modules/vgmodal/js/vgmodal.js +2 -1
- package/app/modules/vgsidebar/js/vgsidebar.js +1 -0
- package/app/modules/vgtabs/index.js +4 -0
- package/app/modules/vgtabs/js/vgtabs.js +384 -0
- package/app/modules/vgtabs/scss/_variables.scss +29 -0
- package/app/modules/vgtabs/scss/vgtabs.scss +112 -0
- package/app/modules/vgtoast/js/vgtoast.js +1 -0
- package/app/utils/js/functions.js +29 -1
- package/app/utils/scss/variables.scss +9 -4
- package/build/vgapp.css +1 -0
- package/build/vgapp.css.map +1 -1
- package/build/vgapp.js +1 -1
- package/build/vgapp.js.map +1 -1
- package/index.js +2 -1
- package/package.json +1 -1
- package/webpack.config.js +1 -1
- package/public/assets/build/vgapp.css +0 -18
- package/public/assets/build/vgapp.css.map +0 -1
- package/public/assets/build/vgapp.js +0 -3
- package/public/assets/build/vgapp.js.LICENSE.txt +0 -1
- package/public/assets/build/vgapp.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -16,6 +16,7 @@ class BaseModule {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
this._params = {};
|
|
19
|
+
this._isLoaded = false;
|
|
19
20
|
Data.set(this._element, this.constructor.NAME_KEY, this);
|
|
20
21
|
}
|
|
21
22
|
|
|
@@ -36,6 +37,8 @@ class BaseModule {
|
|
|
36
37
|
const _this = this;
|
|
37
38
|
let $content = null;
|
|
38
39
|
|
|
40
|
+
if (_this._isLoaded) return;
|
|
41
|
+
|
|
39
42
|
const setData = (data) => {
|
|
40
43
|
if ($content) $content.innerHTML = data;
|
|
41
44
|
};
|
|
@@ -61,6 +64,10 @@ class BaseModule {
|
|
|
61
64
|
}
|
|
62
65
|
|
|
63
66
|
Ajax[_this._params.ajax.method](_this._params.ajax.route, _this._params.ajax.data || {}, function (status, data) {
|
|
67
|
+
if ('once' in _this._params.ajax && _this._params.ajax.once) {
|
|
68
|
+
_this._isLoaded = true;
|
|
69
|
+
}
|
|
70
|
+
|
|
64
71
|
setData(data.response);
|
|
65
72
|
execute(callback, [status, data]);
|
|
66
73
|
});
|
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
import BaseModule from "../../base-module";
|
|
2
|
+
import Selectors from "../../../utils/js/dom/selectors";
|
|
3
|
+
import EventHandler from "../../../utils/js/dom/event";
|
|
4
|
+
import {getNextActiveElement, isDisabled, mergeDeepObject} from "../../../utils/js/functions";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Constants
|
|
8
|
+
*/
|
|
9
|
+
const NAME = 'tabs';
|
|
10
|
+
const NAME_KEY = 'vg.tabs';
|
|
11
|
+
|
|
12
|
+
const EVENT_HIDE = `${NAME_KEY}.hide`;
|
|
13
|
+
const EVENT_HIDDEN = `${NAME_KEY}.hidden`;
|
|
14
|
+
const EVENT_SHOW = `${NAME_KEY}.show`;
|
|
15
|
+
const EVENT_SHOWN = `${NAME_KEY}.shown`;
|
|
16
|
+
const EVENT_LOADED = `${NAME_KEY}.loaded`;
|
|
17
|
+
|
|
18
|
+
const EVENT_KEYDOWN = `keydown.${NAME_KEY}`;
|
|
19
|
+
const EVENT_LOAD_DATA_API = `load.${NAME_KEY}`;
|
|
20
|
+
const EVENT_CLICK_DATA_API = `click.${NAME_KEY}`;
|
|
21
|
+
const EVENT_MOUSEOVER_DATA_API = `mouseover.${NAME_KEY}`;
|
|
22
|
+
const EVENT_MOUSEOUT_DATA_API = `mouseout.${NAME_KEY}`;
|
|
23
|
+
|
|
24
|
+
const ARROW_LEFT_KEY = 'ArrowLeft';
|
|
25
|
+
const ARROW_RIGHT_KEY = 'ArrowRight';
|
|
26
|
+
const ARROW_UP_KEY = 'ArrowUp';
|
|
27
|
+
const ARROW_DOWN_KEY = 'ArrowDown';
|
|
28
|
+
const HOME_KEY = 'Home';
|
|
29
|
+
const END_KEY = 'End';
|
|
30
|
+
|
|
31
|
+
const CLASS_NAME_ACTIVE = 'active';
|
|
32
|
+
const CLASS_NAME_HOVER = 'hover';
|
|
33
|
+
const CLASS_NAME_FADE = 'fade';
|
|
34
|
+
const CLASS_NAME_SHOW = 'show';
|
|
35
|
+
const CLASS_DROPDOWN = 'dropdown';
|
|
36
|
+
const CLASS_SLIDER = 'vg-tabs-slider';
|
|
37
|
+
const CLASS_WITH_SLIDER = 'vg-tabs-with-slider';
|
|
38
|
+
|
|
39
|
+
const SELECTOR_DROPDOWN_TOGGLE = '[data-vg-toggle="dropdown"]';
|
|
40
|
+
const SELECTOR_DROPDOWN_MENU = '.dropdown-content';
|
|
41
|
+
const NOT_SELECTOR_DROPDOWN_TOGGLE = `:not(${SELECTOR_DROPDOWN_TOGGLE})`;
|
|
42
|
+
|
|
43
|
+
const SELECTOR_TAB_CLASS = '.vg-tabs';
|
|
44
|
+
const SELECTOR_TAB_PANEL = '.list-group, .vg-tabs-panel, [role="tablist"]';
|
|
45
|
+
const SELECTOR_OUTER = '.vg-tabs-item, .list-group-item';
|
|
46
|
+
const SELECTOR_INNER = `.vg-tabs-link${NOT_SELECTOR_DROPDOWN_TOGGLE}, .list-group-item${NOT_SELECTOR_DROPDOWN_TOGGLE}, [role="tab"]${NOT_SELECTOR_DROPDOWN_TOGGLE}`;
|
|
47
|
+
const SELECTOR_DATA_TOGGLE = '[data-vg-toggle="tab"]';
|
|
48
|
+
const SELECTOR_INNER_ELEM = `${SELECTOR_INNER}, ${SELECTOR_DATA_TOGGLE}`;
|
|
49
|
+
|
|
50
|
+
const SELECTOR_DATA_TOGGLE_ACTIVE = `.${CLASS_NAME_ACTIVE}[data-vg-toggle="tab"]`;
|
|
51
|
+
|
|
52
|
+
class VGTabs extends BaseModule {
|
|
53
|
+
|
|
54
|
+
constructor(element, params) {
|
|
55
|
+
super(element, params);
|
|
56
|
+
|
|
57
|
+
this._params = mergeDeepObject({
|
|
58
|
+
slide: false,
|
|
59
|
+
hash: false,
|
|
60
|
+
ajax: {
|
|
61
|
+
route: '',
|
|
62
|
+
target: '',
|
|
63
|
+
method: 'get',
|
|
64
|
+
loader: false,
|
|
65
|
+
once: true
|
|
66
|
+
},
|
|
67
|
+
}, this._params);
|
|
68
|
+
|
|
69
|
+
this._parent = this._element.closest(SELECTOR_TAB_PANEL);
|
|
70
|
+
this._main_parent = this._parent.closest(SELECTOR_TAB_CLASS);
|
|
71
|
+
this._params = this._getParams(this._main_parent, this._params);
|
|
72
|
+
this._params = this._getParams(this._element, this._params);
|
|
73
|
+
|
|
74
|
+
if (!this._parent) {
|
|
75
|
+
throw new TypeError(`${element.outerHTML} не имеет родителя ${SELECTOR_INNER_ELEM}`)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
this._setInitialAttributes(this._parent, this._getChildren());
|
|
79
|
+
this._setInitialSlider();
|
|
80
|
+
this._setTabHash();
|
|
81
|
+
|
|
82
|
+
EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event))
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
static get NAME() {
|
|
86
|
+
return NAME;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
static get NAME_KEY() {
|
|
90
|
+
return NAME_KEY
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
show() {
|
|
94
|
+
const innerElem = this._element
|
|
95
|
+
if (this._elemIsActive(innerElem)) {
|
|
96
|
+
return
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const active = this._getActiveElem()
|
|
100
|
+
|
|
101
|
+
const hideEvent = active ?
|
|
102
|
+
EventHandler.trigger(active, EVENT_HIDE, { relatedTarget: innerElem }) :
|
|
103
|
+
null
|
|
104
|
+
|
|
105
|
+
const showEvent = EventHandler.trigger(innerElem, EVENT_SHOW, { relatedTarget: active })
|
|
106
|
+
|
|
107
|
+
if (showEvent.defaultPrevented || (hideEvent && hideEvent.defaultPrevented)) {
|
|
108
|
+
return
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
this._deactivate(active, innerElem)
|
|
112
|
+
this._activate(innerElem, active)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
_elemIsActive(elem) {
|
|
116
|
+
return elem.classList.contains(CLASS_NAME_ACTIVE)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
_getActiveElem() {
|
|
120
|
+
return this._getChildren().find(child => this._elemIsActive(child)) || null
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
_activate(element, relatedElem) {
|
|
124
|
+
if (!element) {
|
|
125
|
+
return
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
element.classList.add(CLASS_NAME_ACTIVE);
|
|
129
|
+
|
|
130
|
+
this._activate(Selectors.getElementFromSelector(element));
|
|
131
|
+
|
|
132
|
+
const complete = () => {
|
|
133
|
+
if (element.getAttribute('role') !== 'tab') {
|
|
134
|
+
element.classList.add(CLASS_NAME_SHOW)
|
|
135
|
+
return
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
this._route((status, data) => {
|
|
139
|
+
EventHandler.trigger(this._element, EVENT_LOADED, {stats: status, data: data});
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
element.removeAttribute('tabindex')
|
|
143
|
+
element.setAttribute('aria-selected', true);
|
|
144
|
+
|
|
145
|
+
this._toggleDropDown(element, true)
|
|
146
|
+
EventHandler.trigger(element, EVENT_SHOWN, {
|
|
147
|
+
relatedTarget: relatedElem
|
|
148
|
+
})
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE))
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
_deactivate(element, relatedElem) {
|
|
155
|
+
if (!element) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
element.classList.remove(CLASS_NAME_ACTIVE);
|
|
160
|
+
element.blur();
|
|
161
|
+
|
|
162
|
+
this._deactivate(Selectors.getElementFromSelector(element));
|
|
163
|
+
|
|
164
|
+
const complete = () => {
|
|
165
|
+
if (element.getAttribute('role') !== 'tab') {
|
|
166
|
+
element.classList.remove(CLASS_NAME_SHOW);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
element.setAttribute('aria-selected', false);
|
|
171
|
+
element.setAttribute('tabindex', '-1');
|
|
172
|
+
this._toggleDropDown(element, false);
|
|
173
|
+
EventHandler.trigger(element, EVENT_HIDDEN, { relatedTarget: relatedElem });
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE));
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
_keydown(event) {
|
|
180
|
+
if (!([ARROW_LEFT_KEY, ARROW_RIGHT_KEY, ARROW_UP_KEY, ARROW_DOWN_KEY, HOME_KEY, END_KEY].includes(event.key))) {
|
|
181
|
+
return
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
event.stopPropagation()// stopPropagation/preventDefault both added to support up/down keys without scrolling the page
|
|
185
|
+
event.preventDefault()
|
|
186
|
+
|
|
187
|
+
const children = this._getChildren().filter(element => !isDisabled(element))
|
|
188
|
+
let nextActiveElement
|
|
189
|
+
|
|
190
|
+
if ([HOME_KEY, END_KEY].includes(event.key)) {
|
|
191
|
+
nextActiveElement = children[event.key === HOME_KEY ? 0 : children.length - 1]
|
|
192
|
+
} else {
|
|
193
|
+
const isNext = [ARROW_RIGHT_KEY, ARROW_DOWN_KEY].includes(event.key)
|
|
194
|
+
nextActiveElement = getNextActiveElement(children, event.target, isNext, true)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (nextActiveElement) {
|
|
198
|
+
nextActiveElement.focus({ preventScroll: true })
|
|
199
|
+
VGTabs.getOrCreateInstance(nextActiveElement).show()
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
_setTabHash() {
|
|
204
|
+
if (!this._params.hash) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
let url = document.location.toString();
|
|
209
|
+
|
|
210
|
+
if (url.match('#')) {
|
|
211
|
+
let id = url.split('#')[1];
|
|
212
|
+
|
|
213
|
+
let element = Selectors.find('[href="#' + id +'"]', this._parent) || Selectors.find('[data-vg-target="#' + id +'"]', this._element) || null;
|
|
214
|
+
if (element) {
|
|
215
|
+
VGTabs.getOrCreateInstance(element).show();
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
_setInitialSlider() {
|
|
221
|
+
if (!this._params.slide) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
let slider = Selectors.find('.' + CLASS_SLIDER, this._main_parent);
|
|
226
|
+
if (!slider) {
|
|
227
|
+
slider = document.createElement('span');
|
|
228
|
+
slider.classList.add(CLASS_SLIDER);
|
|
229
|
+
this._main_parent.prepend(slider);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
this._main_parent.classList.add(CLASS_WITH_SLIDER);
|
|
233
|
+
|
|
234
|
+
let link_active = Selectors.find('.' + CLASS_NAME_ACTIVE, this._parent),
|
|
235
|
+
{width, height} = window.getComputedStyle(link_active);
|
|
236
|
+
|
|
237
|
+
link_active.classList.add(CLASS_NAME_HOVER);
|
|
238
|
+
|
|
239
|
+
slider.style.width = width;
|
|
240
|
+
slider.style.height = height;
|
|
241
|
+
slider.style.left = link_active.offsetLeft + 'px';
|
|
242
|
+
|
|
243
|
+
EventHandler.on(this._main_parent, EVENT_MOUSEOVER_DATA_API, SELECTOR_DATA_TOGGLE, (event) => {
|
|
244
|
+
let link_target = event.target,
|
|
245
|
+
{width, height} = window.getComputedStyle(link_target);
|
|
246
|
+
|
|
247
|
+
if (['A', 'AREA'].includes(event.target.tagName)) {
|
|
248
|
+
event.preventDefault();
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (isDisabled(link_target)) return;
|
|
252
|
+
|
|
253
|
+
let link_current_hover = Selectors.find('.' + CLASS_NAME_HOVER, this._parent);
|
|
254
|
+
if (link_current_hover) link_current_hover.classList.remove(CLASS_NAME_HOVER);
|
|
255
|
+
link_target.classList.add(CLASS_NAME_HOVER);
|
|
256
|
+
|
|
257
|
+
slider.style.width = width;
|
|
258
|
+
slider.style.height = height;
|
|
259
|
+
slider.style.left = link_target.offsetLeft + 'px';
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
EventHandler.on(this._main_parent, EVENT_MOUSEOUT_DATA_API, SELECTOR_DATA_TOGGLE, (event) => {
|
|
263
|
+
if (['A', 'AREA'].includes(event.target.tagName)) {
|
|
264
|
+
event.preventDefault();
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
let active = Selectors.find('.' + CLASS_NAME_ACTIVE, this._parent),
|
|
268
|
+
{width, height} = window.getComputedStyle(active);
|
|
269
|
+
|
|
270
|
+
[... Selectors.findAll('.' + CLASS_NAME_HOVER, this._parent)].forEach(el => {
|
|
271
|
+
el.classList.remove(CLASS_NAME_HOVER);
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
active.classList.add(CLASS_NAME_HOVER);
|
|
275
|
+
|
|
276
|
+
slider.style.width = width;
|
|
277
|
+
slider.style.height = height;
|
|
278
|
+
slider.style.left = active.offsetLeft + 'px';
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
_setInitialAttributes(parent, children) {
|
|
283
|
+
this._setAttributeIfNotExists(parent, 'role', 'tablist')
|
|
284
|
+
|
|
285
|
+
for (const child of children) {
|
|
286
|
+
this._setInitialAttributesOnChild(child)
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
_setInitialAttributesOnChild(child) {
|
|
291
|
+
child = this._getInnerElement(child)
|
|
292
|
+
const isActive = this._elemIsActive(child)
|
|
293
|
+
const outerElem = this._getOuterElement(child)
|
|
294
|
+
child.setAttribute('aria-selected', isActive)
|
|
295
|
+
|
|
296
|
+
if (outerElem !== child) {
|
|
297
|
+
this._setAttributeIfNotExists(outerElem, 'role', 'presentation')
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (!isActive) {
|
|
301
|
+
child.setAttribute('tabindex', '-1')
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
this._setAttributeIfNotExists(child, 'role', 'tab')
|
|
305
|
+
this._setInitialAttributesOnTargetPanel(child)
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
_setInitialAttributesOnTargetPanel(child) {
|
|
309
|
+
const target = Selectors.getElementFromSelector(child)
|
|
310
|
+
|
|
311
|
+
if (!target) {
|
|
312
|
+
return
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
this._setAttributeIfNotExists(target, 'role', 'tabpanel')
|
|
316
|
+
|
|
317
|
+
if (child.id) {
|
|
318
|
+
this._setAttributeIfNotExists(target, 'aria-labelledby', `${child.id}`)
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
_setAttributeIfNotExists(element, attribute, value) {
|
|
323
|
+
if (!element.hasAttribute(attribute)) {
|
|
324
|
+
element.setAttribute(attribute, value)
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
_getChildren() {
|
|
329
|
+
return Selectors.findAll(SELECTOR_INNER_ELEM, this._parent)
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
_getInnerElement(elem) {
|
|
333
|
+
return elem.matches(SELECTOR_INNER_ELEM) ? elem : Selectors.find(SELECTOR_INNER_ELEM, elem)
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
_getOuterElement(elem) {
|
|
337
|
+
return elem.closest(SELECTOR_OUTER) || elem
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
_toggleDropDown(element, open) {
|
|
341
|
+
const outerElem = this._getOuterElement(element)
|
|
342
|
+
if (!outerElem.classList.contains(CLASS_DROPDOWN)) {
|
|
343
|
+
return
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const toggle = (selector, className) => {
|
|
347
|
+
const element = Selectors.find(selector, outerElem)
|
|
348
|
+
if (element) {
|
|
349
|
+
element.classList.toggle(className, open)
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
toggle(SELECTOR_DROPDOWN_TOGGLE, CLASS_NAME_ACTIVE)
|
|
354
|
+
toggle(SELECTOR_DROPDOWN_MENU, CLASS_NAME_SHOW)
|
|
355
|
+
outerElem.setAttribute('aria-expanded', open)
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Data API implementation
|
|
361
|
+
*/
|
|
362
|
+
EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
|
|
363
|
+
if (['A', 'AREA'].includes(this.tagName)) {
|
|
364
|
+
event.preventDefault();
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
if (isDisabled(this)) {
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
VGTabs.getOrCreateInstance(this).show();
|
|
372
|
+
})
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Initialize on focus
|
|
376
|
+
*/
|
|
377
|
+
EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
|
|
378
|
+
for (const element of Selectors.findAll(SELECTOR_DATA_TOGGLE_ACTIVE)) {
|
|
379
|
+
VGTabs.getOrCreateInstance(element);
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
export default VGTabs;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
$tabs-map: (
|
|
2
|
+
panel-gap: 10px,
|
|
3
|
+
panel-margin-bottom: 1.5rem,
|
|
4
|
+
link-border-radius: $border-radius,
|
|
5
|
+
link-border-style: $border-style,
|
|
6
|
+
link-border-width: $border-width,
|
|
7
|
+
link-border-color: $border-color,
|
|
8
|
+
link-border-active-color: $border-color-active,
|
|
9
|
+
link-border-disabled-color: $border-color-disabled,
|
|
10
|
+
link-color: $color,
|
|
11
|
+
link-active-color: $color-active,
|
|
12
|
+
link-focus-color: $color-active,
|
|
13
|
+
link-disabled-color: $color-disabled,
|
|
14
|
+
link-bg: transparent,
|
|
15
|
+
link-active-bg: transparent,
|
|
16
|
+
link-focus-bg: transparent,
|
|
17
|
+
link-disabled-bg: transparent,
|
|
18
|
+
link-padding-x: 16px,
|
|
19
|
+
link-padding-y: 8px,
|
|
20
|
+
link-transition: $transition-base,
|
|
21
|
+
slider-bg: $color-active,
|
|
22
|
+
slider-link-color: white,
|
|
23
|
+
slider-border-radius: $border-radius,
|
|
24
|
+
slider-transition: $transition-base,
|
|
25
|
+
track-slider-padding-x: 6px,
|
|
26
|
+
track-slider-padding-y: 6px,
|
|
27
|
+
track-slider-border-radius: 6px,
|
|
28
|
+
track-slider-bg: rgba(white, .1),
|
|
29
|
+
);
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*--------------------------------------------------------------------------
|
|
3
|
+
* Модуль: VGTabs
|
|
4
|
+
* Автор: Vegas DEV
|
|
5
|
+
* Лицензия: смотри LICENSE
|
|
6
|
+
*--------------------------------------------------------------------------
|
|
7
|
+
**/
|
|
8
|
+
|
|
9
|
+
@import "../../../utils/scss/functions";
|
|
10
|
+
@import "../../../utils/scss/mixin";
|
|
11
|
+
@import "../../../utils/scss/variables";
|
|
12
|
+
@import "variables";
|
|
13
|
+
|
|
14
|
+
.vg-tabs {
|
|
15
|
+
@include mix-vars('tabs', $tabs-map);
|
|
16
|
+
|
|
17
|
+
&-panel {
|
|
18
|
+
display: flex;
|
|
19
|
+
flex-wrap: wrap;
|
|
20
|
+
padding-left: 0;
|
|
21
|
+
margin-bottom: 0;
|
|
22
|
+
list-style: none;
|
|
23
|
+
gap: var(--vg-tabs-panel-gap);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
&-link {
|
|
27
|
+
display: block;
|
|
28
|
+
text-decoration: none;
|
|
29
|
+
padding: var(--vg-tabs-link-padding-y) var(--vg-tabs-link-padding-x);
|
|
30
|
+
color: var(--vg-tabs-link-color);
|
|
31
|
+
background-color: var(--vg-tabs-link-bg);
|
|
32
|
+
border-width: var(--vg-tabs-link-border-width);
|
|
33
|
+
border-style: var(--vg-tabs-link-border-style);
|
|
34
|
+
border-color: var(--vg-tabs-link-border-color);
|
|
35
|
+
border-radius: var(--vg-tabs-link-border-radius);
|
|
36
|
+
transition: var(--vg-tabs-link-transition);
|
|
37
|
+
|
|
38
|
+
&:focus {
|
|
39
|
+
color: var(--vg-tabs-link-focus-color);
|
|
40
|
+
background-color: var(--vg-tabs-link-focus-bg);
|
|
41
|
+
border-color: var(--vg-tabs-link-border-focus-color);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
&.active {
|
|
45
|
+
color: var(--vg-tabs-link-active-color);
|
|
46
|
+
background-color: var(--vg-tabs-link-active-bg);
|
|
47
|
+
border-color: var(--vg-tabs-link-border-active-color);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
&[disabled] {
|
|
51
|
+
cursor: not-allowed;
|
|
52
|
+
color: var(--vg-tabs-link-disabled-color);
|
|
53
|
+
background-color: var(--vg-tabs-link-disabled-bg);
|
|
54
|
+
border-color: var(--vg-tabs-link-border-disabled-color);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
&-column {
|
|
59
|
+
flex-direction: column;
|
|
60
|
+
|
|
61
|
+
.vg-tabs-item {
|
|
62
|
+
flex: 1;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.vg-tabs-link {
|
|
66
|
+
width: 100%;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
&-with-slider {
|
|
71
|
+
--vg-tabs-link-border-width: 0;
|
|
72
|
+
padding: var(--vg-tabs-track-slider-padding-y) var(--vg-tabs-track-slider-padding-x);
|
|
73
|
+
border-radius: var(--vg-tabs-track-slider-border-radius);
|
|
74
|
+
background-color: var(--vg-tabs-track-slider-bg);
|
|
75
|
+
position: relative;
|
|
76
|
+
|
|
77
|
+
.vg-tabs-slider {
|
|
78
|
+
position: absolute;
|
|
79
|
+
background-color: var(--vg-tabs-slider-bg);
|
|
80
|
+
border-radius: var(--vg-tabs-slider-border-radius);
|
|
81
|
+
transition: var(--vg-tabs-slider-transition);
|
|
82
|
+
z-index: 0;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.vg-tabs-panel {
|
|
86
|
+
justify-content: space-between;
|
|
87
|
+
|
|
88
|
+
.vg-tabs-item {
|
|
89
|
+
flex: 1;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.vg-tabs-link {
|
|
93
|
+
width: 100%;
|
|
94
|
+
position: relative;
|
|
95
|
+
z-index: 10;
|
|
96
|
+
|
|
97
|
+
&.active, &.hover {
|
|
98
|
+
color: var(--vg-tabs-slider-link-color);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.vg-tabs-content {
|
|
106
|
+
> .vg-tabs-pane {
|
|
107
|
+
display: none;
|
|
108
|
+
}
|
|
109
|
+
> .active {
|
|
110
|
+
display: block;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -317,9 +317,37 @@ function transliterate(text, enToRu) {
|
|
|
317
317
|
return text;
|
|
318
318
|
}
|
|
319
319
|
|
|
320
|
+
/**
|
|
321
|
+
* Возвращает предыдущий/следующий элемент списка.
|
|
322
|
+
*
|
|
323
|
+
* @param {array} list The list of elements
|
|
324
|
+
* @param activeElement The active element
|
|
325
|
+
* @param shouldGetNext Choose to get next or previous element
|
|
326
|
+
* @param isCycleAllowed
|
|
327
|
+
* @return {Element|elem} The proper element
|
|
328
|
+
*/
|
|
329
|
+
const getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => {
|
|
330
|
+
const listLength = list.length
|
|
331
|
+
let index = list.indexOf(activeElement)
|
|
332
|
+
|
|
333
|
+
// if the element does not exist in the list return an element
|
|
334
|
+
// depending on the direction and if cycle is allowed
|
|
335
|
+
if (index === -1) {
|
|
336
|
+
return !shouldGetNext && isCycleAllowed ? list[listLength - 1] : list[0]
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
index += shouldGetNext ? 1 : -1
|
|
340
|
+
|
|
341
|
+
if (isCycleAllowed) {
|
|
342
|
+
index = (index + listLength) % listLength
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return list[Math.max(0, Math.min(index, listLength - 1))]
|
|
346
|
+
}
|
|
347
|
+
|
|
320
348
|
/**
|
|
321
349
|
*
|
|
322
350
|
*/
|
|
323
351
|
const isRTL = () => document.documentElement.dir === 'rtl'
|
|
324
352
|
|
|
325
|
-
export {isElement, isVisible, isDisabled, isObject, isEmptyObj, mergeDeepObject, removeElementArray, normalizeData, execute, executeAfterTransition, reflow, noop, makeRandomString, isRTL, transliterate, getElement}
|
|
353
|
+
export {isElement, isVisible, isDisabled, isObject, isEmptyObj, mergeDeepObject, removeElementArray, normalizeData, execute, executeAfterTransition, reflow, noop, makeRandomString, isRTL, transliterate, getElement, getNextActiveElement}
|
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
// -- Backgrounds
|
|
2
2
|
$bg-color: #fff !default;
|
|
3
|
+
$bg-color-active: #c7dcf6 !default;
|
|
3
4
|
|
|
4
5
|
// -- Colors
|
|
5
6
|
$color: #000000 !default;
|
|
7
|
+
$color-active: #0065ff !default;
|
|
8
|
+
$color-disabled: rgba(#000000, .5) !default;
|
|
6
9
|
|
|
7
10
|
// -- Shadows
|
|
8
11
|
$box-shadow: 0 8px 14px 5px rgba(0, 0, 0, 0.2) !default;
|
|
9
12
|
|
|
10
13
|
// -- Borders
|
|
11
|
-
$border-color:
|
|
12
|
-
$border-
|
|
13
|
-
$border-
|
|
14
|
-
$border-
|
|
14
|
+
$border-color: rgba(0, 0, 0, .2) !default;
|
|
15
|
+
$border-color-active: rgba(#0065ff, 1) !default;
|
|
16
|
+
$border-color-disabled: rgba(0, 0, 0, .1) !default;
|
|
17
|
+
$border-radius: .375rem !default;
|
|
18
|
+
$border-width: 1px !default;
|
|
19
|
+
$border-style: solid;
|
|
15
20
|
|
|
16
21
|
// -- Transitions
|
|
17
22
|
$transition-base: all .5s ease-in-out !default;
|