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.
Files changed (47) hide show
  1. package/components/air-datepicker/air-datepicker.js +152 -0
  2. package/components/alert/alert.js +54 -0
  3. package/components/button/buttons.js +220 -0
  4. package/components/card/cards.js +149 -0
  5. package/components/carousel/carousel.js +574 -0
  6. package/components/carousel/slider.js +340 -0
  7. package/components/chip/chips.js +341 -0
  8. package/components/collapsible/collapsible.js +156 -0
  9. package/components/color-input/color-input.js +166 -0
  10. package/components/datepicker/datepicker.js +1035 -0
  11. package/components/dialog/materialbox.js +377 -0
  12. package/components/dialog/modal.js +72 -0
  13. package/components/dropdown/dropdown.js +505 -0
  14. package/components/file-input/file-input.js +169 -0
  15. package/components/kanban/_kanban.scss +69 -0
  16. package/components/kanban/kanban.js +168 -0
  17. package/components/kanban/kanban.ts +57 -8
  18. package/components/loading/_loading.scss +68 -0
  19. package/components/loading/loading.ts +104 -0
  20. package/components/loading/loadingSpec.js +102 -0
  21. package/components/navigation-drawer/sidenav.js +454 -0
  22. package/components/number-input/number-input.js +68 -0
  23. package/components/password-input/password-input.js +49 -0
  24. package/components/popup/_popup.scss +106 -0
  25. package/components/popup/popup.ts +113 -0
  26. package/components/popup/popupSpec.js +140 -0
  27. package/components/search/autocomplete.js +470 -0
  28. package/components/slider/range.js +169 -0
  29. package/components/snackbar/toasts.js +244 -0
  30. package/components/tabs/tabs.js +289 -0
  31. package/components/textfield/forms.js +172 -0
  32. package/components/textfield/select.js +385 -0
  33. package/components/timepicker/timepicker.js +698 -0
  34. package/components/tom-select/tom-select-field.js +130 -0
  35. package/components/toolbar/toolbar.js +134 -0
  36. package/components/tooltip/tooltip.js +270 -0
  37. package/dist/css/materialize.colors.min.css +1 -1
  38. package/dist/css/materialize.css +322 -1
  39. package/dist/css/materialize.min.css +2 -2
  40. package/dist/css/materialize.min.css.map +1 -1
  41. package/dist/js/materialize.cjs.js +258 -42
  42. package/dist/js/materialize.d.ts +50 -3
  43. package/dist/js/materialize.js +258 -42
  44. package/dist/js/materialize.min.js +2 -2
  45. package/dist/js/materialize.mjs +257 -43
  46. package/package.json +6 -1
  47. 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
+ }