kmaterialize 2.3.3-1.0.21 → 2.3.3-1.0.23
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/components/air-datepicker/air-datepicker.js +152 -0
- package/components/alert/alert.js +54 -0
- package/components/button/buttons.js +220 -0
- package/components/card/cards.js +149 -0
- package/components/carousel/carousel.js +574 -0
- package/components/carousel/slider.js +340 -0
- package/components/chip/chips.js +341 -0
- package/components/collapsible/collapsible.js +156 -0
- package/components/color-input/color-input.js +166 -0
- package/components/datepicker/datepicker.js +1035 -0
- package/components/dialog/materialbox.js +377 -0
- package/components/dialog/modal.js +72 -0
- package/components/dropdown/dropdown.js +505 -0
- package/components/file-input/file-input.js +169 -0
- package/components/kanban/_kanban.scss +69 -0
- package/components/kanban/kanban.js +168 -0
- package/components/kanban/kanban.ts +57 -8
- package/components/loading/_loading.scss +68 -0
- package/components/loading/loading.ts +104 -0
- package/components/loading/loadingSpec.js +102 -0
- package/components/navigation-drawer/sidenav.js +454 -0
- package/components/number-input/number-input.js +68 -0
- package/components/password-input/password-input.js +49 -0
- package/components/popup/_popup.scss +106 -0
- package/components/popup/popup.ts +113 -0
- package/components/popup/popupSpec.js +140 -0
- package/components/search/autocomplete.js +470 -0
- package/components/slider/range.js +169 -0
- package/components/snackbar/toasts.js +244 -0
- package/components/tabs/tabs.js +289 -0
- package/components/textfield/forms.js +172 -0
- package/components/textfield/select.js +385 -0
- package/components/timepicker/timepicker.js +698 -0
- package/components/tom-select/tom-select-field.js +130 -0
- package/components/toolbar/toolbar.js +134 -0
- package/components/tooltip/tooltip.js +270 -0
- package/dist/css/materialize.colors.min.css +1 -1
- package/dist/css/materialize.css +322 -1
- package/dist/css/materialize.min.css +2 -2
- package/dist/css/materialize.min.css.map +1 -1
- package/dist/js/materialize.cjs.js +258 -42
- package/dist/js/materialize.d.ts +50 -3
- package/dist/js/materialize.js +258 -42
- package/dist/js/materialize.min.js +2 -2
- package/dist/js/materialize.mjs +257 -43
- package/package.json +6 -1
- package/sass/materialize.scss +2 -0
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
const _defaults = {
|
|
2
|
+
text: '',
|
|
3
|
+
displayLength: 4000,
|
|
4
|
+
inDuration: 300,
|
|
5
|
+
outDuration: 375,
|
|
6
|
+
classes: '',
|
|
7
|
+
completeCallback: null,
|
|
8
|
+
activationPercent: 0.8
|
|
9
|
+
};
|
|
10
|
+
export class Toast {
|
|
11
|
+
/** The toast element. */
|
|
12
|
+
el;
|
|
13
|
+
/**
|
|
14
|
+
* The remaining amount of time in ms that the toast
|
|
15
|
+
* will stay before dismissal.
|
|
16
|
+
*/
|
|
17
|
+
timeRemaining;
|
|
18
|
+
/**
|
|
19
|
+
* Describes the current pan state of the Toast.
|
|
20
|
+
*/
|
|
21
|
+
panning;
|
|
22
|
+
options;
|
|
23
|
+
message;
|
|
24
|
+
counterInterval;
|
|
25
|
+
wasSwiped;
|
|
26
|
+
startingXPos;
|
|
27
|
+
xPos;
|
|
28
|
+
time;
|
|
29
|
+
deltaX;
|
|
30
|
+
velocityX;
|
|
31
|
+
static _toasts;
|
|
32
|
+
static _container;
|
|
33
|
+
static _draggedToast;
|
|
34
|
+
constructor(options) {
|
|
35
|
+
this.options = {
|
|
36
|
+
...Toast.defaults,
|
|
37
|
+
...options
|
|
38
|
+
};
|
|
39
|
+
this.message = this.options.text;
|
|
40
|
+
this.panning = false;
|
|
41
|
+
this.timeRemaining = this.options.displayLength;
|
|
42
|
+
if (!Toast._container) {
|
|
43
|
+
Toast._createContainer();
|
|
44
|
+
}
|
|
45
|
+
// Create new toast
|
|
46
|
+
Toast._toasts.push(this);
|
|
47
|
+
const toastElement = this._createToast();
|
|
48
|
+
toastElement['M_Toast'] = this;
|
|
49
|
+
this.el = toastElement;
|
|
50
|
+
this._animateIn();
|
|
51
|
+
this._setTimer();
|
|
52
|
+
}
|
|
53
|
+
static get defaults() {
|
|
54
|
+
return _defaults;
|
|
55
|
+
}
|
|
56
|
+
static getInstance(el) {
|
|
57
|
+
return el['M_Toast'];
|
|
58
|
+
}
|
|
59
|
+
static _createContainer() {
|
|
60
|
+
const container = document.createElement('div');
|
|
61
|
+
container.setAttribute('id', 'toast-container');
|
|
62
|
+
// Add event handler
|
|
63
|
+
container.addEventListener('touchstart', Toast._onDragStart);
|
|
64
|
+
container.addEventListener('touchmove', Toast._onDragMove);
|
|
65
|
+
container.addEventListener('touchend', Toast._onDragEnd);
|
|
66
|
+
container.addEventListener('mousedown', Toast._onDragStart);
|
|
67
|
+
document.addEventListener('mousemove', Toast._onDragMove);
|
|
68
|
+
document.addEventListener('mouseup', Toast._onDragEnd);
|
|
69
|
+
document.body.appendChild(container);
|
|
70
|
+
Toast._container = container;
|
|
71
|
+
}
|
|
72
|
+
static _removeContainer() {
|
|
73
|
+
document.removeEventListener('mousemove', Toast._onDragMove);
|
|
74
|
+
document.removeEventListener('mouseup', Toast._onDragEnd);
|
|
75
|
+
if (Toast._container) {
|
|
76
|
+
Toast._container.remove();
|
|
77
|
+
Toast._container = null;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
static _onDragStart(e) {
|
|
81
|
+
if (e.target && e.target.closest('.toast')) {
|
|
82
|
+
const toastElem = e.target.closest('.toast');
|
|
83
|
+
const toast = toastElem['M_Toast'];
|
|
84
|
+
toast.panning = true;
|
|
85
|
+
Toast._draggedToast = toast;
|
|
86
|
+
toast.el.classList.add('panning');
|
|
87
|
+
toast.el.style.transition = '';
|
|
88
|
+
toast.startingXPos = Toast._xPos(e);
|
|
89
|
+
toast.time = Date.now();
|
|
90
|
+
toast.xPos = Toast._xPos(e);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
static _onDragMove(e) {
|
|
94
|
+
if (!!Toast._draggedToast) {
|
|
95
|
+
e.preventDefault();
|
|
96
|
+
const toast = Toast._draggedToast;
|
|
97
|
+
toast.deltaX = Math.abs(toast.xPos - Toast._xPos(e));
|
|
98
|
+
toast.xPos = Toast._xPos(e);
|
|
99
|
+
toast.velocityX = toast.deltaX / (Date.now() - toast.time);
|
|
100
|
+
toast.time = Date.now();
|
|
101
|
+
const totalDeltaX = toast.xPos - toast.startingXPos;
|
|
102
|
+
const activationDistance = toast.el.offsetWidth * toast.options.activationPercent;
|
|
103
|
+
toast.el.style.transform = `translateX(${totalDeltaX}px)`;
|
|
104
|
+
toast.el.style.opacity = (1 - Math.abs(totalDeltaX / activationDistance)).toString();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
static _onDragEnd() {
|
|
108
|
+
if (!!Toast._draggedToast) {
|
|
109
|
+
const toast = Toast._draggedToast;
|
|
110
|
+
toast.panning = false;
|
|
111
|
+
toast.el.classList.remove('panning');
|
|
112
|
+
const totalDeltaX = toast.xPos - toast.startingXPos;
|
|
113
|
+
const activationDistance = toast.el.offsetWidth * toast.options.activationPercent;
|
|
114
|
+
const shouldBeDismissed = Math.abs(totalDeltaX) > activationDistance || toast.velocityX > 1;
|
|
115
|
+
// Remove toast
|
|
116
|
+
if (shouldBeDismissed) {
|
|
117
|
+
toast.wasSwiped = true;
|
|
118
|
+
toast.dismiss();
|
|
119
|
+
// Animate toast back to original position
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
toast.el.style.transition = 'transform .2s, opacity .2s';
|
|
123
|
+
toast.el.style.transform = '';
|
|
124
|
+
toast.el.style.opacity = '';
|
|
125
|
+
}
|
|
126
|
+
Toast._draggedToast = null;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
static _xPos(e) {
|
|
130
|
+
if (e.type.startsWith('touch') && e.targetTouches.length >= 1) {
|
|
131
|
+
return e.targetTouches[0].clientX;
|
|
132
|
+
}
|
|
133
|
+
// mouse event
|
|
134
|
+
return e.clientX;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* dismiss all toasts.
|
|
138
|
+
*/
|
|
139
|
+
static dismissAll() {
|
|
140
|
+
for (const toastIndex in Toast._toasts) {
|
|
141
|
+
Toast._toasts[toastIndex].dismiss();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
_createToast() {
|
|
145
|
+
let toast = this.options.toastId
|
|
146
|
+
? document.getElementById(this.options.toastId)
|
|
147
|
+
: document.createElement('div');
|
|
148
|
+
if (toast instanceof HTMLTemplateElement) {
|
|
149
|
+
const node = toast.content.cloneNode(true);
|
|
150
|
+
toast = node.firstElementChild;
|
|
151
|
+
}
|
|
152
|
+
toast.classList.add('toast');
|
|
153
|
+
toast.setAttribute('role', 'alert');
|
|
154
|
+
toast.setAttribute('aria-live', 'assertive');
|
|
155
|
+
toast.setAttribute('aria-atomic', 'true');
|
|
156
|
+
// Add custom classes onto toast
|
|
157
|
+
if (this.options.classes.length > 0) {
|
|
158
|
+
toast.classList.add(...this.options.classes.split(' '));
|
|
159
|
+
}
|
|
160
|
+
if (this.message)
|
|
161
|
+
toast.innerText = this.message;
|
|
162
|
+
if (Toast._container) {
|
|
163
|
+
Toast._container.appendChild(toast);
|
|
164
|
+
}
|
|
165
|
+
return toast;
|
|
166
|
+
}
|
|
167
|
+
_animateIn() {
|
|
168
|
+
// Animate toast in
|
|
169
|
+
this.el.style.display = '';
|
|
170
|
+
this.el.style.opacity = '0';
|
|
171
|
+
// easeOutCubic
|
|
172
|
+
this.el.style.transition = `
|
|
173
|
+
top ${this.options.inDuration}ms ease,
|
|
174
|
+
opacity ${this.options.inDuration}ms ease
|
|
175
|
+
`;
|
|
176
|
+
setTimeout(() => {
|
|
177
|
+
this.el.style.top = '0';
|
|
178
|
+
this.el.style.opacity = '1';
|
|
179
|
+
}, 1);
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Create setInterval which automatically removes toast when timeRemaining >= 0
|
|
183
|
+
* has been reached.
|
|
184
|
+
*/
|
|
185
|
+
_setTimer() {
|
|
186
|
+
if (this.timeRemaining !== Infinity) {
|
|
187
|
+
this.counterInterval = setInterval(() => {
|
|
188
|
+
// If toast is not being dragged, decrease its time remaining
|
|
189
|
+
if (!this.panning) {
|
|
190
|
+
this.timeRemaining -= 20;
|
|
191
|
+
}
|
|
192
|
+
// Animate toast out
|
|
193
|
+
if (this.timeRemaining <= 0) {
|
|
194
|
+
this.dismiss();
|
|
195
|
+
}
|
|
196
|
+
}, 20);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Dismiss toast with animation.
|
|
201
|
+
*/
|
|
202
|
+
dismiss() {
|
|
203
|
+
clearInterval(this.counterInterval);
|
|
204
|
+
const activationDistance = this.el.offsetWidth * this.options.activationPercent;
|
|
205
|
+
if (this.wasSwiped) {
|
|
206
|
+
this.el.style.transition = 'transform .05s, opacity .05s';
|
|
207
|
+
this.el.style.transform = `translateX(${activationDistance}px)`;
|
|
208
|
+
this.el.style.opacity = '0';
|
|
209
|
+
}
|
|
210
|
+
// easeOutExpo
|
|
211
|
+
this.el.style.transition = `
|
|
212
|
+
margin ${this.options.outDuration}ms ease,
|
|
213
|
+
opacity ${this.options.outDuration}ms ease`;
|
|
214
|
+
setTimeout(() => {
|
|
215
|
+
this.el.style.opacity = '0';
|
|
216
|
+
this.el.style.marginTop = '-40px';
|
|
217
|
+
}, 1);
|
|
218
|
+
setTimeout(() => {
|
|
219
|
+
// Call the optional callback
|
|
220
|
+
if (typeof this.options.completeCallback === 'function') {
|
|
221
|
+
this.options.completeCallback();
|
|
222
|
+
}
|
|
223
|
+
// Remove toast from DOM
|
|
224
|
+
if (this.el.id != this.options.toastId) {
|
|
225
|
+
this.el.remove();
|
|
226
|
+
const toastIndex = Toast._toasts.indexOf(this);
|
|
227
|
+
// indexOf returns -1 if this toast is no longer tracked (e.g. the
|
|
228
|
+
// static state was already reset elsewhere); splice(-1, 1) would
|
|
229
|
+
// otherwise silently remove an unrelated, still-active toast.
|
|
230
|
+
if (toastIndex !== -1) {
|
|
231
|
+
Toast._toasts.splice(toastIndex, 1);
|
|
232
|
+
}
|
|
233
|
+
if (Toast._toasts.length === 0) {
|
|
234
|
+
Toast._removeContainer();
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}, this.options.outDuration);
|
|
238
|
+
}
|
|
239
|
+
static {
|
|
240
|
+
Toast._toasts = [];
|
|
241
|
+
Toast._container = null;
|
|
242
|
+
Toast._draggedToast = null;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import { Carousel } from '../carousel/carousel';
|
|
2
|
+
import { Component } from '../../src/component';
|
|
3
|
+
const _defaults = {
|
|
4
|
+
duration: 300,
|
|
5
|
+
onShow: null,
|
|
6
|
+
swipeable: false,
|
|
7
|
+
responsiveThreshold: Infinity // breakpoint for swipeable
|
|
8
|
+
};
|
|
9
|
+
export class Tabs extends Component {
|
|
10
|
+
_tabLinks;
|
|
11
|
+
_index;
|
|
12
|
+
_indicator;
|
|
13
|
+
_tabWidth;
|
|
14
|
+
_tabsWidth;
|
|
15
|
+
_tabsCarousel;
|
|
16
|
+
_activeTabLink;
|
|
17
|
+
_content;
|
|
18
|
+
constructor(el, options) {
|
|
19
|
+
super(el, options, Tabs);
|
|
20
|
+
this.el['M_Tabs'] = this;
|
|
21
|
+
this.options = {
|
|
22
|
+
...Tabs.defaults,
|
|
23
|
+
...options
|
|
24
|
+
};
|
|
25
|
+
this._tabLinks = this.el.querySelectorAll('li.tab > a');
|
|
26
|
+
this._index = 0;
|
|
27
|
+
this._setupActiveTabLink();
|
|
28
|
+
if (this.options.swipeable) {
|
|
29
|
+
this._setupSwipeableTabs();
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
this._setupNormalTabs();
|
|
33
|
+
}
|
|
34
|
+
// Setup tabs indicator after content to ensure accurate widths
|
|
35
|
+
this._setTabsAndTabWidth();
|
|
36
|
+
this._createIndicator();
|
|
37
|
+
this._setupEventHandlers();
|
|
38
|
+
}
|
|
39
|
+
static get defaults() {
|
|
40
|
+
return _defaults;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Initializes instances of Tabs.
|
|
44
|
+
* @param els HTML elements.
|
|
45
|
+
* @param options Component options.
|
|
46
|
+
*/
|
|
47
|
+
static init(els, options = {}) {
|
|
48
|
+
return super.init(els, options, Tabs);
|
|
49
|
+
}
|
|
50
|
+
static getInstance(el) {
|
|
51
|
+
return el['M_Tabs'];
|
|
52
|
+
}
|
|
53
|
+
destroy() {
|
|
54
|
+
this._removeEventHandlers();
|
|
55
|
+
this._indicator.parentNode.removeChild(this._indicator);
|
|
56
|
+
if (this.options.swipeable) {
|
|
57
|
+
this._teardownSwipeableTabs();
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
this._teardownNormalTabs();
|
|
61
|
+
}
|
|
62
|
+
this.el['M_Tabs'] = undefined;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* The index of tab that is currently shown.
|
|
66
|
+
*/
|
|
67
|
+
get index() {
|
|
68
|
+
return this._index;
|
|
69
|
+
}
|
|
70
|
+
_setupEventHandlers() {
|
|
71
|
+
window.addEventListener('resize', this._handleWindowResize);
|
|
72
|
+
this.el.addEventListener('click', this._handleTabClick);
|
|
73
|
+
// map vertical scrolling to horizontal scrolling because no scrollbar is shown on desktop
|
|
74
|
+
this.el.addEventListener('wheel', (event) => {
|
|
75
|
+
if (event.deltaY !== 0) {
|
|
76
|
+
event.preventDefault();
|
|
77
|
+
this.el.scrollLeft += event.deltaY * 1;
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
_removeEventHandlers() {
|
|
82
|
+
window.removeEventListener('resize', this._handleWindowResize);
|
|
83
|
+
this.el.removeEventListener('click', this._handleTabClick);
|
|
84
|
+
}
|
|
85
|
+
_handleWindowResize = () => {
|
|
86
|
+
this._setTabsAndTabWidth();
|
|
87
|
+
if (this._tabWidth !== 0 && this._tabsWidth !== 0) {
|
|
88
|
+
this._indicator.style.left = this._calcLeftPos(this._activeTabLink) + 'px';
|
|
89
|
+
this._indicator.style.right = this._calcRightPos(this._activeTabLink) + 'px';
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
_handleTabClick = (e) => {
|
|
93
|
+
let tabLink = e.target;
|
|
94
|
+
if (!tabLink)
|
|
95
|
+
return;
|
|
96
|
+
let tab = tabLink.parentElement;
|
|
97
|
+
while (tab && !tab.classList.contains('tab')) {
|
|
98
|
+
tabLink = tabLink.parentElement;
|
|
99
|
+
tab = tab.parentElement;
|
|
100
|
+
}
|
|
101
|
+
// Handle click on tab link only
|
|
102
|
+
if (!tabLink || !tab.classList.contains('tab'))
|
|
103
|
+
return;
|
|
104
|
+
// is disabled?
|
|
105
|
+
if (tab.classList.contains('disabled')) {
|
|
106
|
+
e.preventDefault();
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
// Act as regular link if target attribute is specified.
|
|
110
|
+
if (tabLink.hasAttribute('target'))
|
|
111
|
+
return;
|
|
112
|
+
// Make the old tab inactive.
|
|
113
|
+
this._activeTabLink.classList.remove('active');
|
|
114
|
+
const _oldContent = this._content;
|
|
115
|
+
// Update the variables with the new link and content
|
|
116
|
+
this._activeTabLink = tabLink;
|
|
117
|
+
if (tabLink.hash)
|
|
118
|
+
this._content = document.querySelector(tabLink.hash);
|
|
119
|
+
this._tabLinks = this.el.querySelectorAll('li.tab > a');
|
|
120
|
+
// Make the tab active
|
|
121
|
+
this._activeTabLink.classList.add('active');
|
|
122
|
+
const prevIndex = this._index;
|
|
123
|
+
this._index = Math.max(Array.from(this._tabLinks).indexOf(tabLink), 0);
|
|
124
|
+
// Swap content
|
|
125
|
+
if (this.options.swipeable) {
|
|
126
|
+
if (this._tabsCarousel) {
|
|
127
|
+
this._tabsCarousel.set(this._index, () => {
|
|
128
|
+
if (typeof this.options.onShow === 'function')
|
|
129
|
+
this.options.onShow.call(this, this._content);
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
if (this._content) {
|
|
135
|
+
this._content.style.display = 'block';
|
|
136
|
+
this._content.classList.add('active');
|
|
137
|
+
if (typeof this.options.onShow === 'function')
|
|
138
|
+
this.options.onShow.call(this, this._content);
|
|
139
|
+
if (_oldContent && _oldContent !== this._content) {
|
|
140
|
+
_oldContent.style.display = 'none';
|
|
141
|
+
_oldContent.classList.remove('active');
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
// Update widths after content is swapped (scrollbar bugfix)
|
|
146
|
+
this._setTabsAndTabWidth();
|
|
147
|
+
this._animateIndicator(prevIndex);
|
|
148
|
+
e.preventDefault();
|
|
149
|
+
};
|
|
150
|
+
_createIndicator() {
|
|
151
|
+
const indicator = document.createElement('li');
|
|
152
|
+
indicator.classList.add('indicator');
|
|
153
|
+
this.el.appendChild(indicator);
|
|
154
|
+
this._indicator = indicator;
|
|
155
|
+
this._indicator.style.left = this._calcLeftPos(this._activeTabLink) + 'px';
|
|
156
|
+
this._indicator.style.right = this._calcRightPos(this._activeTabLink) + 'px';
|
|
157
|
+
}
|
|
158
|
+
_setupActiveTabLink() {
|
|
159
|
+
// If the location.hash matches one of the links, use that as the active tab.
|
|
160
|
+
this._activeTabLink = Array.from(this._tabLinks).find((a) => a.getAttribute('href') === location.hash);
|
|
161
|
+
// If no match is found, use the first link or any with class 'active' as the initial active tab.
|
|
162
|
+
if (!this._activeTabLink) {
|
|
163
|
+
let activeTabLink = this.el.querySelector('li.tab a.active');
|
|
164
|
+
if (!activeTabLink) {
|
|
165
|
+
activeTabLink = this.el.querySelector('li.tab a');
|
|
166
|
+
}
|
|
167
|
+
this._activeTabLink = activeTabLink;
|
|
168
|
+
}
|
|
169
|
+
Array.from(this._tabLinks).forEach((a) => a.classList.remove('active'));
|
|
170
|
+
this._activeTabLink.classList.add('active');
|
|
171
|
+
this._index = Math.max(Array.from(this._tabLinks).indexOf(this._activeTabLink), 0);
|
|
172
|
+
if (this._activeTabLink && this._activeTabLink.hash) {
|
|
173
|
+
this._content = document.querySelector(this._activeTabLink.hash);
|
|
174
|
+
if (this._content)
|
|
175
|
+
this._content.classList.add('active');
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
_setupSwipeableTabs() {
|
|
179
|
+
// Change swipeable according to responsive threshold
|
|
180
|
+
if (window.innerWidth > this.options.responsiveThreshold)
|
|
181
|
+
this.options.swipeable = false;
|
|
182
|
+
const tabsContent = [];
|
|
183
|
+
this._tabLinks.forEach((a) => {
|
|
184
|
+
if (a.hash) {
|
|
185
|
+
const currContent = document.querySelector(a.hash);
|
|
186
|
+
currContent.classList.add('carousel-item');
|
|
187
|
+
tabsContent.push(currContent);
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
// Create Carousel-Wrapper around Tab-Contents
|
|
191
|
+
const tabsWrapper = document.createElement('div');
|
|
192
|
+
tabsWrapper.classList.add('tabs-content', 'carousel', 'carousel-slider');
|
|
193
|
+
// Wrap around
|
|
194
|
+
tabsContent[0].parentElement.insertBefore(tabsWrapper, tabsContent[0]);
|
|
195
|
+
tabsContent.forEach((tabContent) => {
|
|
196
|
+
tabsWrapper.appendChild(tabContent);
|
|
197
|
+
tabContent.style.display = '';
|
|
198
|
+
});
|
|
199
|
+
// Keep active tab index to set initial carousel slide
|
|
200
|
+
const tab = this._activeTabLink.parentElement;
|
|
201
|
+
const activeTabIndex = Array.from(tab.parentNode.children).indexOf(tab);
|
|
202
|
+
this._tabsCarousel = Carousel.init(tabsWrapper, {
|
|
203
|
+
fullWidth: true,
|
|
204
|
+
noWrap: true,
|
|
205
|
+
onCycleTo: (item) => {
|
|
206
|
+
const prevIndex = this._index;
|
|
207
|
+
this._index = Array.from(item.parentNode.children).indexOf(item);
|
|
208
|
+
this._activeTabLink.classList.remove('active');
|
|
209
|
+
this._activeTabLink = Array.from(this._tabLinks)[this._index];
|
|
210
|
+
this._activeTabLink.classList.add('active');
|
|
211
|
+
this._animateIndicator(prevIndex);
|
|
212
|
+
if (typeof this.options.onShow === 'function')
|
|
213
|
+
this.options.onShow.call(this, this._content);
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
// Set initial carousel slide to active tab
|
|
217
|
+
this._tabsCarousel.set(activeTabIndex);
|
|
218
|
+
}
|
|
219
|
+
_teardownSwipeableTabs() {
|
|
220
|
+
const tabsWrapper = this._tabsCarousel.el;
|
|
221
|
+
this._tabsCarousel.destroy();
|
|
222
|
+
// Unwrap
|
|
223
|
+
tabsWrapper.append(tabsWrapper.parentElement);
|
|
224
|
+
tabsWrapper.remove();
|
|
225
|
+
}
|
|
226
|
+
_setupNormalTabs() {
|
|
227
|
+
// Hide Tabs Content
|
|
228
|
+
Array.from(this._tabLinks).forEach((a) => {
|
|
229
|
+
if (a === this._activeTabLink)
|
|
230
|
+
return;
|
|
231
|
+
if (a.hash) {
|
|
232
|
+
const currContent = document.querySelector(a.hash);
|
|
233
|
+
if (currContent)
|
|
234
|
+
currContent.style.display = 'none';
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
_teardownNormalTabs() {
|
|
239
|
+
// show Tabs Content
|
|
240
|
+
this._tabLinks.forEach((a) => {
|
|
241
|
+
if (a.hash) {
|
|
242
|
+
const currContent = document.querySelector(a.hash);
|
|
243
|
+
if (currContent)
|
|
244
|
+
currContent.style.display = '';
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
_setTabsAndTabWidth() {
|
|
249
|
+
this._tabsWidth = this.el.getBoundingClientRect().width;
|
|
250
|
+
this._tabWidth = Math.max(this._tabsWidth, this.el.scrollWidth) / this._tabLinks.length;
|
|
251
|
+
}
|
|
252
|
+
_calcRightPos(el) {
|
|
253
|
+
return Math.ceil(this._tabsWidth - el.offsetLeft - el.getBoundingClientRect().width);
|
|
254
|
+
}
|
|
255
|
+
_calcLeftPos(el) {
|
|
256
|
+
return Math.floor(el.offsetLeft);
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Recalculate tab indicator position. This is useful when
|
|
260
|
+
* the indicator position is not correct.
|
|
261
|
+
*/
|
|
262
|
+
updateTabIndicator() {
|
|
263
|
+
this._setTabsAndTabWidth();
|
|
264
|
+
this._animateIndicator(this._index);
|
|
265
|
+
}
|
|
266
|
+
_animateIndicator(prevIndex) {
|
|
267
|
+
let leftDelay = 0, rightDelay = 0;
|
|
268
|
+
const isMovingLeftOrStaying = this._index - prevIndex >= 0;
|
|
269
|
+
if (isMovingLeftOrStaying)
|
|
270
|
+
leftDelay = 90;
|
|
271
|
+
else
|
|
272
|
+
rightDelay = 90;
|
|
273
|
+
// in v1: easeOutQuad
|
|
274
|
+
this._indicator.style.transition = `
|
|
275
|
+
left ${this.options.duration}ms ease-out ${leftDelay}ms,
|
|
276
|
+
right ${this.options.duration}ms ease-out ${rightDelay}ms`;
|
|
277
|
+
this._indicator.style.left = this._calcLeftPos(this._activeTabLink) + 'px';
|
|
278
|
+
this._indicator.style.right = this._calcRightPos(this._activeTabLink) + 'px';
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Show tab content that corresponds to the tab with the id.
|
|
282
|
+
* @param tabId The id of the tab that you want to switch to.
|
|
283
|
+
*/
|
|
284
|
+
select(tabId) {
|
|
285
|
+
const tab = Array.from(this._tabLinks).find((a) => a.getAttribute('href') === '#' + tabId);
|
|
286
|
+
if (tab)
|
|
287
|
+
tab.click();
|
|
288
|
+
}
|
|
289
|
+
}
|