@materializecss/materialize 1.2.2 → 2.0.1-alpha
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/Gruntfile.js +68 -313
- package/README.md +26 -14
- package/dist/css/materialize.css +1009 -1822
- package/dist/css/materialize.min.css +2 -8
- package/dist/js/materialize.js +8414 -12299
- package/dist/js/materialize.min.js +8968 -2
- package/dist/js/materialize.min.js.map +1 -0
- package/package.json +13 -9
- package/sass/components/_badges.scss +12 -2
- package/sass/components/_buttons.scss +16 -11
- package/sass/components/_cards.scss +14 -9
- package/sass/components/_carousel.scss +5 -2
- package/sass/components/_chips.scss +3 -3
- package/sass/components/_collapsible.scss +22 -8
- package/sass/components/_collection.scss +14 -6
- package/sass/components/_datepicker.scss +30 -11
- package/sass/components/_dropdown.scss +6 -4
- package/sass/components/_global.scss +132 -111
- package/sass/components/_grid.scss +119 -98
- package/sass/components/_modal.scss +3 -3
- package/sass/components/_navbar.scss +31 -17
- package/sass/components/_normalize.scss +26 -124
- package/sass/components/_sidenav.scss +21 -20
- package/sass/components/_slider.scss +27 -7
- package/sass/components/_table_of_contents.scss +12 -12
- package/sass/components/_tabs.scss +47 -16
- package/sass/components/_tapTarget.scss +6 -6
- package/sass/components/_theme_variables.scss +98 -0
- package/sass/components/_timepicker.scss +54 -46
- package/sass/components/_toast.scss +3 -3
- package/sass/components/_tooltip.scss +4 -5
- package/sass/components/_typography.scss +1 -1
- package/sass/components/_variables.scss +185 -120
- package/sass/components/forms/_checkboxes.scss +9 -9
- package/sass/components/forms/_file-input.scss +9 -7
- package/sass/components/forms/_input-fields.scss +173 -234
- package/sass/components/forms/_radio-buttons.scss +1 -1
- package/sass/components/forms/_range.scss +11 -11
- package/sass/components/forms/_select.scss +29 -19
- package/sass/components/forms/_switches.scss +22 -18
- package/sass/materialize.scss +1 -1
- package/src/autocomplete.ts +459 -0
- package/src/bounding.ts +6 -0
- package/{js/buttons.js → src/buttons.ts} +103 -162
- package/src/cards.ts +54 -0
- package/{js/carousel.js → src/carousel.ts} +137 -262
- package/src/characterCounter.ts +88 -0
- package/src/chips.ts +350 -0
- package/src/collapsible.ts +184 -0
- package/{js/component.js → src/component.ts} +6 -19
- package/{js/datepicker.js → src/datepicker.ts} +213 -299
- package/{js/dropdown.js → src/dropdown.ts} +140 -254
- package/src/edges.ts +6 -0
- package/src/forms.ts +120 -0
- package/src/global.ts +385 -0
- package/src/materialbox.ts +348 -0
- package/src/modal.ts +256 -0
- package/{js/parallax.js → src/parallax.ts} +47 -60
- package/{js/pushpin.js → src/pushpin.ts} +19 -47
- package/{js/range.js → src/range.ts} +58 -139
- package/{js/scrollspy.js → src/scrollspy.ts} +81 -153
- package/src/select.ts +448 -0
- package/{js/sidenav.js → src/sidenav.ts} +96 -202
- package/src/slider.ts +415 -0
- package/src/tabs.ts +293 -0
- package/src/tapTarget.ts +240 -0
- package/{js/timepicker.js → src/timepicker.ts} +268 -272
- package/{js/toasts.js → src/toasts.ts} +75 -134
- package/{js/tooltip.js → src/tooltip.ts} +59 -96
- package/src/waves.ts +70 -0
- package/extras/noUiSlider/nouislider.css +0 -404
- package/extras/noUiSlider/nouislider.js +0 -2147
- package/extras/noUiSlider/nouislider.min.js +0 -1
- package/js/anime.min.js +0 -34
- package/js/autocomplete.js +0 -479
- package/js/cards.js +0 -40
- package/js/cash.js +0 -960
- package/js/characterCounter.js +0 -136
- package/js/chips.js +0 -486
- package/js/collapsible.js +0 -275
- package/js/forms.js +0 -285
- package/js/global.js +0 -428
- package/js/materialbox.js +0 -453
- package/js/modal.js +0 -382
- package/js/select.js +0 -391
- package/js/slider.js +0 -497
- package/js/tabs.js +0 -402
- package/js/tapTarget.js +0 -315
- package/js/waves.js +0 -615
- package/sass/components/_waves.scss +0 -187
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { Component } from "./component";
|
|
2
|
+
|
|
3
|
+
let _defaults = {};
|
|
4
|
+
|
|
5
|
+
export class CharacterCounter extends Component {
|
|
6
|
+
isInvalid: boolean;
|
|
7
|
+
isValidLength: boolean;
|
|
8
|
+
private _handleUpdateCounterBound: any;
|
|
9
|
+
counterEl: HTMLSpanElement;
|
|
10
|
+
|
|
11
|
+
constructor(el: Element, options: Object) {
|
|
12
|
+
super(CharacterCounter, el, options);
|
|
13
|
+
(this.el as any).M_CharacterCounter = this;
|
|
14
|
+
this.options = {...CharacterCounter.defaults, ...options};
|
|
15
|
+
this.isInvalid = false;
|
|
16
|
+
this.isValidLength = false;
|
|
17
|
+
this._setupCounter();
|
|
18
|
+
this._setupEventHandlers();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
static get defaults() {
|
|
22
|
+
return _defaults;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static init(els, options) {
|
|
26
|
+
return super.init(this, els, options);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
static getInstance(el) {
|
|
30
|
+
let domElem = !!el.jquery ? el[0] : el;
|
|
31
|
+
return domElem.M_CharacterCounter;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
destroy() {
|
|
35
|
+
this._removeEventHandlers();
|
|
36
|
+
(this.el as any).CharacterCounter = undefined;
|
|
37
|
+
this._removeCounter();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
_setupEventHandlers() {
|
|
41
|
+
this._handleUpdateCounterBound = this.updateCounter.bind(this);
|
|
42
|
+
this.el.addEventListener('focus', this._handleUpdateCounterBound, true);
|
|
43
|
+
this.el.addEventListener('input', this._handleUpdateCounterBound, true);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
_removeEventHandlers() {
|
|
47
|
+
this.el.removeEventListener('focus', this._handleUpdateCounterBound, true);
|
|
48
|
+
this.el.removeEventListener('input', this._handleUpdateCounterBound, true);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
_setupCounter() {
|
|
52
|
+
this.counterEl = document.createElement('span');
|
|
53
|
+
this.counterEl.classList.add('character-counter');
|
|
54
|
+
this.counterEl.style.float = 'right';
|
|
55
|
+
this.counterEl.style.fontSize = '12px';
|
|
56
|
+
this.counterEl.style.height = '1';
|
|
57
|
+
this.el.parentElement.appendChild(this.counterEl);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
_removeCounter() {
|
|
61
|
+
this.counterEl.remove();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
updateCounter() {
|
|
65
|
+
let maxLength = parseInt(this.el.getAttribute('data-length')),
|
|
66
|
+
actualLength = (this.el as HTMLInputElement).value.length;
|
|
67
|
+
|
|
68
|
+
this.isValidLength = actualLength <= maxLength;
|
|
69
|
+
let counterString = actualLength.toString();
|
|
70
|
+
if (maxLength) {
|
|
71
|
+
counterString += '/' + maxLength;
|
|
72
|
+
this._validateInput();
|
|
73
|
+
}
|
|
74
|
+
this.counterEl.innerHTML = counterString;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
_validateInput() {
|
|
78
|
+
if (this.isValidLength && this.isInvalid) {
|
|
79
|
+
this.isInvalid = false;
|
|
80
|
+
this.el.classList.remove('invalid');
|
|
81
|
+
}
|
|
82
|
+
else if (!this.isValidLength && !this.isInvalid) {
|
|
83
|
+
this.isInvalid = true;
|
|
84
|
+
this.el.classList.remove('valid');
|
|
85
|
+
this.el.classList.add('invalid');
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
package/src/chips.ts
ADDED
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
import { Component } from "./component";
|
|
2
|
+
import { M } from "./global";
|
|
3
|
+
import { Autocomplete } from "./autocomplete";
|
|
4
|
+
|
|
5
|
+
let _defaults = {
|
|
6
|
+
data: [],
|
|
7
|
+
placeholder: '',
|
|
8
|
+
secondaryPlaceholder: '',
|
|
9
|
+
autocompleteOptions: {},
|
|
10
|
+
autocompleteOnly: false,
|
|
11
|
+
limit: Infinity,
|
|
12
|
+
onChipAdd: null,
|
|
13
|
+
onChipSelect: null,
|
|
14
|
+
onChipDelete: null
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
interface DataBit {
|
|
18
|
+
id: string, // required
|
|
19
|
+
text?: string,
|
|
20
|
+
image?: string,
|
|
21
|
+
description?: string,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function gGetIndex(el: HTMLElement): number {
|
|
25
|
+
return [...el.parentNode.children].indexOf(el);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export class Chips extends Component {
|
|
29
|
+
chipsData: DataBit[];
|
|
30
|
+
hasAutocomplete: boolean;
|
|
31
|
+
autocomplete: Autocomplete;
|
|
32
|
+
_input: HTMLInputElement;
|
|
33
|
+
_label: any;
|
|
34
|
+
_chips: HTMLElement[];
|
|
35
|
+
private _handleChipClickBound: any;
|
|
36
|
+
private _handleInputKeydownBound: any;
|
|
37
|
+
private _handleInputFocusBound: any;
|
|
38
|
+
private _handleInputBlurBound: any;
|
|
39
|
+
static _keydown: boolean;
|
|
40
|
+
private _selectedChip: any;
|
|
41
|
+
|
|
42
|
+
constructor(el, options) {
|
|
43
|
+
super(Chips, el, options);
|
|
44
|
+
(this.el as any).M_Chips = this;
|
|
45
|
+
this.options = {...Chips.defaults, ...options};
|
|
46
|
+
|
|
47
|
+
this.el.classList.add('chips', 'input-field');
|
|
48
|
+
this.chipsData = [];
|
|
49
|
+
this._chips = [];
|
|
50
|
+
this._setupInput();
|
|
51
|
+
this.hasAutocomplete = Object.keys(this.options.autocompleteOptions).length > 0;
|
|
52
|
+
|
|
53
|
+
// Set input id
|
|
54
|
+
if (!this._input.getAttribute('id'))
|
|
55
|
+
this._input.setAttribute('id', M.guid());
|
|
56
|
+
|
|
57
|
+
// Render initial chips
|
|
58
|
+
if (this.options.data.length) {
|
|
59
|
+
this.chipsData = this.options.data;
|
|
60
|
+
this._renderChips();
|
|
61
|
+
}
|
|
62
|
+
// Setup autocomplete if needed
|
|
63
|
+
if (this.hasAutocomplete) this._setupAutocomplete();
|
|
64
|
+
this._setPlaceholder();
|
|
65
|
+
this._setupLabel();
|
|
66
|
+
this._setupEventHandlers();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
static get defaults() {
|
|
70
|
+
return _defaults;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
static init(els, options) {
|
|
74
|
+
return super.init(this, els, options);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
static getInstance(el) {
|
|
78
|
+
const domElem = !!el.jquery ? el[0] : el;
|
|
79
|
+
return domElem.M_Chips;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
getData() {
|
|
83
|
+
return this.chipsData;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
destroy() {
|
|
87
|
+
this._removeEventHandlers();
|
|
88
|
+
this._chips.forEach(c => c.remove());
|
|
89
|
+
this._chips = [];
|
|
90
|
+
(this.el as any).M_Chips = undefined;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
_setupEventHandlers() {
|
|
94
|
+
this._handleChipClickBound = this._handleChipClick.bind(this);
|
|
95
|
+
this._handleInputKeydownBound = this._handleInputKeydown.bind(this);
|
|
96
|
+
this._handleInputFocusBound = this._handleInputFocus.bind(this);
|
|
97
|
+
this._handleInputBlurBound = this._handleInputBlur.bind(this);
|
|
98
|
+
this.el.addEventListener('click', this._handleChipClickBound);
|
|
99
|
+
document.addEventListener('keydown', Chips._handleChipsKeydown);
|
|
100
|
+
document.addEventListener('keyup', Chips._handleChipsKeyup);
|
|
101
|
+
this.el.addEventListener('blur', Chips._handleChipsBlur, true);
|
|
102
|
+
this._input.addEventListener('focus', this._handleInputFocusBound);
|
|
103
|
+
this._input.addEventListener('blur', this._handleInputBlurBound);
|
|
104
|
+
this._input.addEventListener('keydown', this._handleInputKeydownBound);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
_removeEventHandlers() {
|
|
108
|
+
this.el.removeEventListener('click', this._handleChipClickBound);
|
|
109
|
+
document.removeEventListener('keydown', Chips._handleChipsKeydown);
|
|
110
|
+
document.removeEventListener('keyup', Chips._handleChipsKeyup);
|
|
111
|
+
this.el.removeEventListener('blur', Chips._handleChipsBlur, true);
|
|
112
|
+
this._input.removeEventListener('focus', this._handleInputFocusBound);
|
|
113
|
+
this._input.removeEventListener('blur', this._handleInputBlurBound);
|
|
114
|
+
this._input.removeEventListener('keydown', this._handleInputKeydownBound);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
_handleChipClick(e) {
|
|
118
|
+
const _chip = (<HTMLElement>e.target).closest('.chip');
|
|
119
|
+
const clickedClose = (<HTMLElement>e.target).classList.contains('close');
|
|
120
|
+
if (_chip) {
|
|
121
|
+
const index = [..._chip.parentNode.children].indexOf(_chip);
|
|
122
|
+
if (clickedClose) {
|
|
123
|
+
this.deleteChip(index);
|
|
124
|
+
this._input.focus();
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
this.selectChip(index);
|
|
128
|
+
}
|
|
129
|
+
// Default handle click to focus on input
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
this._input.focus();
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
static _handleChipsKeydown(e) {
|
|
137
|
+
Chips._keydown = true;
|
|
138
|
+
const chips = (<HTMLElement>e.target).closest('.chips');
|
|
139
|
+
const chipsKeydown = e.target && chips;
|
|
140
|
+
|
|
141
|
+
// Don't handle keydown inputs on input and textarea
|
|
142
|
+
const tag = (<HTMLElement>e.target).tagName;
|
|
143
|
+
if (tag === 'INPUT' || tag === 'TEXTAREA' || !chipsKeydown) return;
|
|
144
|
+
|
|
145
|
+
const currChips: Chips = (chips as any).M_Chips;
|
|
146
|
+
// backspace and delete
|
|
147
|
+
if (e.keyCode === 8 || e.keyCode === 46) {
|
|
148
|
+
e.preventDefault();
|
|
149
|
+
let selectIndex = currChips.chipsData.length;
|
|
150
|
+
if (currChips._selectedChip) {
|
|
151
|
+
const index = gGetIndex(currChips._selectedChip);
|
|
152
|
+
currChips.deleteChip(index);
|
|
153
|
+
currChips._selectedChip = null;
|
|
154
|
+
// Make sure selectIndex doesn't go negative
|
|
155
|
+
selectIndex = Math.max(index - 1, 0);
|
|
156
|
+
}
|
|
157
|
+
if (currChips.chipsData.length)
|
|
158
|
+
currChips.selectChip(selectIndex);
|
|
159
|
+
else
|
|
160
|
+
currChips._input.focus();
|
|
161
|
+
}
|
|
162
|
+
// left arrow key
|
|
163
|
+
else if (e.keyCode === 37) {
|
|
164
|
+
if (currChips._selectedChip) {
|
|
165
|
+
const selectIndex = gGetIndex(currChips._selectedChip) - 1;
|
|
166
|
+
if (selectIndex < 0) return;
|
|
167
|
+
currChips.selectChip(selectIndex);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// right arrow key
|
|
171
|
+
else if (e.keyCode === 39) {
|
|
172
|
+
if (currChips._selectedChip) {
|
|
173
|
+
const selectIndex = gGetIndex(currChips._selectedChip) + 1;
|
|
174
|
+
if (selectIndex >= currChips.chipsData.length)
|
|
175
|
+
currChips._input.focus();
|
|
176
|
+
else
|
|
177
|
+
currChips.selectChip(selectIndex);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
static _handleChipsKeyup(e) {
|
|
183
|
+
Chips._keydown = false;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
static _handleChipsBlur(e) {
|
|
187
|
+
if (!Chips._keydown && document.hidden) {
|
|
188
|
+
const chips = (<HTMLElement>e.target).closest('.chips');
|
|
189
|
+
const currChips: Chips = (chips as any).M_Chips;
|
|
190
|
+
currChips._selectedChip = null;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
_handleInputFocus() {
|
|
195
|
+
this.el.classList.add('focus');
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
_handleInputBlur() {
|
|
199
|
+
this.el.classList.remove('focus');
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
_handleInputKeydown(e) {
|
|
203
|
+
Chips._keydown = true;
|
|
204
|
+
// enter
|
|
205
|
+
if (e.keyCode === 13) {
|
|
206
|
+
// Override enter if autocompleting.
|
|
207
|
+
if (this.hasAutocomplete && this.autocomplete && this.autocomplete.isOpen) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
e.preventDefault();
|
|
211
|
+
if (!this.hasAutocomplete || (this.hasAutocomplete && !this.options.autocompleteOnly)) {
|
|
212
|
+
this.addChip({id: this._input.value});
|
|
213
|
+
}
|
|
214
|
+
this._input.value = '';
|
|
215
|
+
// delete or left
|
|
216
|
+
}
|
|
217
|
+
else if (
|
|
218
|
+
(e.keyCode === 8 || e.keyCode === 37) &&
|
|
219
|
+
this._input.value === '' &&
|
|
220
|
+
this.chipsData.length
|
|
221
|
+
) {
|
|
222
|
+
e.preventDefault();
|
|
223
|
+
this.selectChip(this.chipsData.length - 1);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
_renderChip(chip: DataBit): HTMLDivElement {
|
|
228
|
+
if (!chip.id) return;
|
|
229
|
+
const renderedChip = document.createElement('div');
|
|
230
|
+
renderedChip.classList.add('chip');
|
|
231
|
+
renderedChip.innerText = chip.text || chip.id;
|
|
232
|
+
renderedChip.setAttribute('tabindex', "0");
|
|
233
|
+
const closeIcon = document.createElement('i');
|
|
234
|
+
closeIcon.classList.add('material-icons', 'close');
|
|
235
|
+
closeIcon.innerText = 'close';
|
|
236
|
+
// attach image if needed
|
|
237
|
+
if (chip.image) {
|
|
238
|
+
const img = document.createElement('img');
|
|
239
|
+
img.setAttribute('src', chip.image);
|
|
240
|
+
renderedChip.insertBefore(img, renderedChip.firstChild);
|
|
241
|
+
}
|
|
242
|
+
renderedChip.appendChild(closeIcon);
|
|
243
|
+
return renderedChip;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
_renderChips() {
|
|
247
|
+
this._chips = []; //.remove();
|
|
248
|
+
for (let i = 0; i < this.chipsData.length; i++) {
|
|
249
|
+
const chipElem = this._renderChip(this.chipsData[i]);
|
|
250
|
+
this.el.appendChild(chipElem);
|
|
251
|
+
this._chips.push(chipElem);
|
|
252
|
+
}
|
|
253
|
+
// move input to end
|
|
254
|
+
this.el.append(this._input);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
_setupAutocomplete() {
|
|
258
|
+
this.options.autocompleteOptions.onAutocomplete = (items) => {
|
|
259
|
+
if (items.length > 0) this.addChip(items[0]);
|
|
260
|
+
this._input.value = '';
|
|
261
|
+
this._input.focus();
|
|
262
|
+
};
|
|
263
|
+
this.autocomplete = Autocomplete.init(this._input, this.options.autocompleteOptions);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
_setupInput() {
|
|
267
|
+
this._input = this.el.querySelector('input');
|
|
268
|
+
if (!this._input) {
|
|
269
|
+
this._input = document.createElement('input');
|
|
270
|
+
this.el.append(this._input);
|
|
271
|
+
}
|
|
272
|
+
this._input.classList.add('input');
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
_setupLabel() {
|
|
276
|
+
this._label = this.el.querySelector('label');
|
|
277
|
+
if (this._label) this._label.setAttribute('for', this._input.getAttribute('id'));
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
_setPlaceholder() {
|
|
281
|
+
if (this.chipsData !== undefined && !this.chipsData.length && this.options.placeholder) {
|
|
282
|
+
this._input.placeholder = this.options.placeholder;
|
|
283
|
+
}
|
|
284
|
+
else if (
|
|
285
|
+
(this.chipsData === undefined || !!this.chipsData.length) &&
|
|
286
|
+
this.options.secondaryPlaceholder
|
|
287
|
+
) {
|
|
288
|
+
this._input.placeholder = this.options.secondaryPlaceholder;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
_isValidAndNotExist(chip: DataBit) {
|
|
293
|
+
const isValid = !!chip.id;
|
|
294
|
+
const doesNotExist = !this.chipsData.some(item => item.id == chip.id);
|
|
295
|
+
return isValid && doesNotExist;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
addChip(chip: DataBit) {
|
|
299
|
+
if (!this._isValidAndNotExist(chip) || this.chipsData.length >= this.options.limit) return;
|
|
300
|
+
const renderedChip = this._renderChip(chip);
|
|
301
|
+
this._chips.push(renderedChip);
|
|
302
|
+
this.chipsData.push(chip);
|
|
303
|
+
//$(this._input).before(renderedChip);
|
|
304
|
+
this._input.before(renderedChip);
|
|
305
|
+
this._setPlaceholder();
|
|
306
|
+
// fire chipAdd callback
|
|
307
|
+
if (typeof this.options.onChipAdd === 'function') {
|
|
308
|
+
this.options.onChipAdd(this.el, renderedChip);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
deleteChip(chipIndex: number) {
|
|
313
|
+
const chip = this._chips[chipIndex];
|
|
314
|
+
this._chips[chipIndex].remove();
|
|
315
|
+
this._chips.splice(chipIndex, 1);
|
|
316
|
+
this.chipsData.splice(chipIndex, 1);
|
|
317
|
+
this._setPlaceholder();
|
|
318
|
+
// fire chipDelete callback
|
|
319
|
+
if (typeof this.options.onChipDelete === 'function') {
|
|
320
|
+
this.options.onChipDelete(this.el, chip);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
selectChip(chipIndex: number) {
|
|
325
|
+
const chip = this._chips[chipIndex];
|
|
326
|
+
this._selectedChip = chip;
|
|
327
|
+
chip.focus();
|
|
328
|
+
// fire chipSelect callback
|
|
329
|
+
if (typeof this.options.onChipSelect === 'function') {
|
|
330
|
+
this.options.onChipSelect(this.el, chip);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
static Init(){
|
|
335
|
+
document.addEventListener("DOMContentLoaded", () => {
|
|
336
|
+
// Handle removal of static chips.
|
|
337
|
+
document.body.addEventListener('click', e => {
|
|
338
|
+
if ((<HTMLElement>e.target).closest('.chip .close')) {
|
|
339
|
+
const chips = (<HTMLElement>e.target).closest('.chips');
|
|
340
|
+
if (chips && (chips as any).M_Chips == undefined) return;
|
|
341
|
+
(<HTMLElement>e.target).closest('.chip').remove();
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
static {
|
|
348
|
+
Chips._keydown = false;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { Component } from "./component";
|
|
2
|
+
import anim from "animejs";
|
|
3
|
+
|
|
4
|
+
const _defaults = {
|
|
5
|
+
accordion: true,
|
|
6
|
+
onOpenStart: undefined,
|
|
7
|
+
onOpenEnd: undefined,
|
|
8
|
+
onCloseStart: undefined,
|
|
9
|
+
onCloseEnd: undefined,
|
|
10
|
+
inDuration: 300,
|
|
11
|
+
outDuration: 300
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export class Collapsible extends Component {
|
|
15
|
+
private _headers: HTMLElement[];
|
|
16
|
+
private _handleCollapsibleClickBound: any;
|
|
17
|
+
private _handleCollapsibleKeydownBound: any;
|
|
18
|
+
|
|
19
|
+
constructor(el, options) {
|
|
20
|
+
super(Collapsible, el, options);
|
|
21
|
+
(this.el as any).M_Collapsible = this;
|
|
22
|
+
this.options = {...Collapsible.defaults, ...options};
|
|
23
|
+
// Setup tab indices
|
|
24
|
+
this._headers = Array.from(this.el.querySelectorAll('li > .collapsible-header'));
|
|
25
|
+
this._headers.forEach(el => el.tabIndex = 0);
|
|
26
|
+
this._setupEventHandlers();
|
|
27
|
+
// Open first active
|
|
28
|
+
const activeBodies: HTMLElement[] = Array.from(this.el.querySelectorAll('li.active > .collapsible-body'));
|
|
29
|
+
if (this.options.accordion)
|
|
30
|
+
if (activeBodies.length > 0)
|
|
31
|
+
activeBodies[0].style.display = 'block'; // Accordion
|
|
32
|
+
else
|
|
33
|
+
activeBodies.forEach(el => el.style.display = 'block'); // Expandables
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
static get defaults() {
|
|
37
|
+
return _defaults;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
static init(els, options) {
|
|
41
|
+
return super.init(this, els, options);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
static getInstance(el) {
|
|
45
|
+
const domElem = !!el.jquery ? el[0] : el;
|
|
46
|
+
return domElem.M_Collapsible;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
destroy() {
|
|
50
|
+
this._removeEventHandlers();
|
|
51
|
+
(this.el as any).M_Collapsible = undefined;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
_setupEventHandlers() {
|
|
55
|
+
this._handleCollapsibleClickBound = this._handleCollapsibleClick.bind(this);
|
|
56
|
+
this._handleCollapsibleKeydownBound = this._handleCollapsibleKeydown.bind(this);
|
|
57
|
+
this.el.addEventListener('click', this._handleCollapsibleClickBound);
|
|
58
|
+
this._headers.forEach(header => header.addEventListener('keydown', this._handleCollapsibleKeydownBound));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
_removeEventHandlers() {
|
|
62
|
+
this.el.removeEventListener('click', this._handleCollapsibleClickBound);
|
|
63
|
+
this._headers.forEach(header => header.removeEventListener('keydown', this._handleCollapsibleKeydownBound));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
_handleCollapsibleClick(e) {
|
|
67
|
+
const header = e.target.closest('.collapsible-header');
|
|
68
|
+
if (e.target && header) {
|
|
69
|
+
const collapsible = header.closest('.collapsible');
|
|
70
|
+
if (collapsible !== this.el) return;
|
|
71
|
+
|
|
72
|
+
const li = header.closest('li');
|
|
73
|
+
const isActive = li.classList.contains('active');
|
|
74
|
+
const index = [...li.parentNode.children].indexOf(li);
|
|
75
|
+
|
|
76
|
+
if (isActive)
|
|
77
|
+
this.close(index);
|
|
78
|
+
else
|
|
79
|
+
this.open(index);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
_handleCollapsibleKeydown(e) {
|
|
84
|
+
if (e.keyCode === 13) {
|
|
85
|
+
this._handleCollapsibleClickBound(e);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
_animateIn(index: number) {
|
|
90
|
+
const li = this.el.children[index];
|
|
91
|
+
if (!li) return;
|
|
92
|
+
const body: HTMLElement = li.querySelector('.collapsible-body');
|
|
93
|
+
anim.remove(body);
|
|
94
|
+
body.style.display = 'block';
|
|
95
|
+
body.style.overflow = 'hidden';
|
|
96
|
+
body.style.height = '0';
|
|
97
|
+
body.style.paddingTop = '';
|
|
98
|
+
body.style.paddingBottom = '';
|
|
99
|
+
const pTop = getComputedStyle(body).paddingTop; // . css('padding-top');
|
|
100
|
+
const pBottom = getComputedStyle(body).paddingBottom; //body.css('padding-bottom');
|
|
101
|
+
const finalHeight = body.scrollHeight;
|
|
102
|
+
body.style.paddingTop = '0';
|
|
103
|
+
body.style.paddingBottom = '0';
|
|
104
|
+
anim({
|
|
105
|
+
targets: body,
|
|
106
|
+
height: finalHeight,
|
|
107
|
+
paddingTop: pTop,
|
|
108
|
+
paddingBottom: pBottom,
|
|
109
|
+
duration: this.options.inDuration,
|
|
110
|
+
easing: 'easeInOutCubic',
|
|
111
|
+
complete: (anim) => {
|
|
112
|
+
body.style.overflow = '';
|
|
113
|
+
body.style.height = '';
|
|
114
|
+
body.style.paddingTop = '';
|
|
115
|
+
body.style.paddingBottom = '';
|
|
116
|
+
// onOpenEnd callback
|
|
117
|
+
if (typeof this.options.onOpenEnd === 'function') {
|
|
118
|
+
this.options.onOpenEnd.call(this, li);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
_animateOut(index: number) {
|
|
125
|
+
const li = this.el.children[index];
|
|
126
|
+
if (!li) return;
|
|
127
|
+
const body: HTMLElement = li.querySelector('.collapsible-body');
|
|
128
|
+
anim.remove(body);
|
|
129
|
+
body.style.overflow = 'hidden';
|
|
130
|
+
anim({
|
|
131
|
+
targets: body,
|
|
132
|
+
height: 0,
|
|
133
|
+
paddingTop: 0,
|
|
134
|
+
paddingBottom: 0,
|
|
135
|
+
duration: this.options.outDuration,
|
|
136
|
+
easing: 'easeInOutCubic',
|
|
137
|
+
complete: () => {
|
|
138
|
+
body.style.overflow = '';
|
|
139
|
+
body.style.height = '';
|
|
140
|
+
body.style.padding = '';
|
|
141
|
+
body.style.display = '';
|
|
142
|
+
// onCloseEnd callback
|
|
143
|
+
if (typeof this.options.onCloseEnd === 'function') {
|
|
144
|
+
this.options.onCloseEnd.call(this, li);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
open(index: number) {
|
|
151
|
+
const listItems = Array.from(this.el.children).filter(c => c.tagName === 'LI');
|
|
152
|
+
const li = listItems[index];
|
|
153
|
+
if (li && !li.classList.contains('active')) {
|
|
154
|
+
// onOpenStart callback
|
|
155
|
+
if (typeof this.options.onOpenStart === 'function') {
|
|
156
|
+
this.options.onOpenStart.call(this, li);
|
|
157
|
+
}
|
|
158
|
+
// Handle accordion behavior
|
|
159
|
+
if (this.options.accordion) {
|
|
160
|
+
const activeLis = listItems.filter(li => li.classList.contains('active'));
|
|
161
|
+
activeLis.forEach(activeLi => {
|
|
162
|
+
const index = listItems.indexOf(activeLi);
|
|
163
|
+
this.close(index);
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
// Animate in
|
|
167
|
+
li.classList.add('active');
|
|
168
|
+
this._animateIn(index);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
close(index: number) {
|
|
173
|
+
const li = Array.from(this.el.children).filter(c => c.tagName === 'LI')[index];
|
|
174
|
+
if (li && li.classList.contains('active')) {
|
|
175
|
+
// onCloseStart callback
|
|
176
|
+
if (typeof this.options.onCloseStart === 'function') {
|
|
177
|
+
this.options.onCloseStart.call(this, li);
|
|
178
|
+
}
|
|
179
|
+
// Animate out
|
|
180
|
+
li.classList.remove('active');
|
|
181
|
+
this._animateOut(index);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
@@ -1,44 +1,31 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
* @param {Element} el
|
|
6
|
-
* @param {Object} options
|
|
7
|
-
*/
|
|
8
|
-
constructor(classDef, el, options) {
|
|
1
|
+
|
|
2
|
+
export class Component {
|
|
3
|
+
|
|
4
|
+
constructor(classDef, protected el: Element, protected options) {
|
|
9
5
|
// Display error if el is valid HTML Element
|
|
10
6
|
if (!(el instanceof Element)) {
|
|
11
7
|
console.error(Error(el + ' is not an HTML Element'));
|
|
12
8
|
}
|
|
13
|
-
|
|
14
9
|
// If exists, destroy and reinitialize in child
|
|
15
10
|
let ins = classDef.getInstance(el);
|
|
16
11
|
if (!!ins) {
|
|
17
12
|
ins.destroy();
|
|
18
13
|
}
|
|
19
|
-
|
|
20
14
|
this.el = el;
|
|
21
|
-
this.$el = cash(el);
|
|
22
15
|
}
|
|
23
16
|
|
|
24
|
-
/**
|
|
25
|
-
* Initializes components
|
|
26
|
-
* @param {class} classDef
|
|
27
|
-
* @param {Element | NodeList | jQuery} els
|
|
28
|
-
* @param {Object} options
|
|
29
|
-
*/
|
|
30
17
|
static init(classDef, els, options) {
|
|
31
18
|
let instances = null;
|
|
32
19
|
if (els instanceof Element) {
|
|
33
20
|
instances = new classDef(els, options);
|
|
34
|
-
}
|
|
21
|
+
}
|
|
22
|
+
else if (!!els && (els.jquery || els.cash || els instanceof NodeList || els instanceof HTMLCollection)) {
|
|
35
23
|
let instancesArr = [];
|
|
36
24
|
for (let i = 0; i < els.length; i++) {
|
|
37
25
|
instancesArr.push(new classDef(els[i], options));
|
|
38
26
|
}
|
|
39
27
|
instances = instancesArr;
|
|
40
28
|
}
|
|
41
|
-
|
|
42
29
|
return instances;
|
|
43
30
|
}
|
|
44
31
|
}
|