@materializecss/materialize 2.0.1-alpha → 2.0.2-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.
Files changed (45) hide show
  1. package/Gruntfile.js +5 -2
  2. package/dist/css/materialize.css +90 -86
  3. package/dist/css/materialize.min.css +2 -2
  4. package/dist/js/materialize.js +2797 -2705
  5. package/dist/js/materialize.min.js +2 -8967
  6. package/dist/js/materialize.min.js.map +1 -1
  7. package/package.json +1 -1
  8. package/sass/components/_collapsible.scss +0 -41
  9. package/sass/components/_global.scss +3 -2
  10. package/sass/components/_icons-material-design.scss +2 -1
  11. package/sass/components/_navbar.scss +6 -3
  12. package/sass/components/_sidenav.scss +66 -37
  13. package/sass/components/_theme_variables.scss +2 -2
  14. package/sass/components/_typography.scss +2 -2
  15. package/sass/components/forms/_input-fields.scss +4 -10
  16. package/sass/materialize.scss +0 -4
  17. package/src/autocomplete.ts +188 -94
  18. package/src/buttons.ts +225 -260
  19. package/src/cards.ts +5 -6
  20. package/src/carousel.ts +611 -542
  21. package/src/characterCounter.ts +50 -21
  22. package/src/chips.ts +152 -63
  23. package/src/collapsible.ts +97 -32
  24. package/src/component.ts +99 -10
  25. package/src/datepicker.ts +905 -726
  26. package/src/dropdown.ts +576 -484
  27. package/src/edges.ts +4 -4
  28. package/src/forms.ts +17 -14
  29. package/src/global.ts +55 -324
  30. package/src/materialbox.ts +354 -298
  31. package/src/modal.ts +296 -211
  32. package/src/parallax.ts +129 -105
  33. package/src/pushpin.ts +148 -103
  34. package/src/range.ts +166 -150
  35. package/src/scrollspy.ts +214 -174
  36. package/src/select.ts +434 -398
  37. package/src/sidenav.ts +447 -381
  38. package/src/slider.ts +421 -362
  39. package/src/tabs.ts +276 -222
  40. package/src/tapTarget.ts +246 -213
  41. package/src/timepicker.ts +738 -614
  42. package/src/toasts.ts +254 -230
  43. package/src/tooltip.ts +315 -252
  44. package/src/utils.ts +271 -0
  45. package/src/waves.ts +10 -10
@@ -1,34 +1,64 @@
1
- import { Component } from "./component";
1
+ import { Component, BaseOptions, InitElements, MElement } from "./component";
2
2
 
3
- let _defaults = {};
3
+ export interface CharacterCounterOptions extends BaseOptions {};
4
4
 
5
- export class CharacterCounter extends Component {
5
+ const _defaults = Object.freeze({});
6
+
7
+ type InputElement = HTMLInputElement | HTMLTextAreaElement;
8
+
9
+ export class CharacterCounter extends Component<{}> {
10
+
11
+ declare el: InputElement;
12
+ /** Stores the reference to the counter HTML element. */
13
+ counterEl: HTMLSpanElement;
14
+ /** Specifies whether the input is valid or not. */
6
15
  isInvalid: boolean;
16
+ /** Specifies whether the input text has valid length or not. */
7
17
  isValidLength: boolean;
8
- private _handleUpdateCounterBound: any;
9
- counterEl: HTMLSpanElement;
10
18
 
11
- constructor(el: Element, options: Object) {
12
- super(CharacterCounter, el, options);
19
+ constructor(el: HTMLInputElement | HTMLTextAreaElement, options: Partial<CharacterCounterOptions>) {
20
+ super(el, {}, CharacterCounter);
13
21
  (this.el as any).M_CharacterCounter = this;
14
- this.options = {...CharacterCounter.defaults, ...options};
22
+
23
+ this.options = {
24
+ ...CharacterCounter.defaults,
25
+ ...options
26
+ };
27
+
15
28
  this.isInvalid = false;
16
29
  this.isValidLength = false;
30
+
17
31
  this._setupCounter();
18
32
  this._setupEventHandlers();
19
33
  }
20
34
 
21
- static get defaults() {
35
+ static get defaults(): CharacterCounterOptions {
22
36
  return _defaults;
23
37
  }
24
38
 
25
- static init(els, options) {
26
- return super.init(this, els, options);
39
+ /**
40
+ * Initializes instance of CharacterCounter.
41
+ * @param el HTML element.
42
+ * @param options Component options.
43
+ */
44
+ static init(el: InputElement, options?: Partial<CharacterCounterOptions>): CharacterCounter;
45
+ /**
46
+ * Initializes instances of CharacterCounter.
47
+ * @param els HTML elements.
48
+ * @param options Component options.
49
+ */
50
+ static init(els: InitElements<InputElement | MElement>, options?: Partial<CharacterCounterOptions>): CharacterCounter[];
51
+ /**
52
+ * Initializes instances of CharacterCounter.
53
+ * @param els HTML elements.
54
+ * @param options Component options.
55
+ */
56
+ static init(els: InputElement | InitElements<InputElement | MElement>, options: Partial<CharacterCounterOptions> = {}): CharacterCounter | CharacterCounter[] {
57
+ return super.init(els, options, CharacterCounter);
27
58
  }
28
59
 
29
- static getInstance(el) {
30
- let domElem = !!el.jquery ? el[0] : el;
31
- return domElem.M_CharacterCounter;
60
+ static getInstance(el: InputElement): CharacterCounter {
61
+ return (el as any).M_CharacterCounter;
32
62
  }
33
63
 
34
64
  destroy() {
@@ -38,14 +68,13 @@ export class CharacterCounter extends Component {
38
68
  }
39
69
 
40
70
  _setupEventHandlers() {
41
- this._handleUpdateCounterBound = this.updateCounter.bind(this);
42
- this.el.addEventListener('focus', this._handleUpdateCounterBound, true);
43
- this.el.addEventListener('input', this._handleUpdateCounterBound, true);
71
+ this.el.addEventListener('focus', this.updateCounter, true);
72
+ this.el.addEventListener('input', this.updateCounter, true);
44
73
  }
45
74
 
46
75
  _removeEventHandlers() {
47
- this.el.removeEventListener('focus', this._handleUpdateCounterBound, true);
48
- this.el.removeEventListener('input', this._handleUpdateCounterBound, true);
76
+ this.el.removeEventListener('focus', this.updateCounter, true);
77
+ this.el.removeEventListener('input', this.updateCounter, true);
49
78
  }
50
79
 
51
80
  _setupCounter() {
@@ -61,8 +90,8 @@ export class CharacterCounter extends Component {
61
90
  this.counterEl.remove();
62
91
  }
63
92
 
64
- updateCounter() {
65
- let maxLength = parseInt(this.el.getAttribute('data-length')),
93
+ updateCounter = () => {
94
+ let maxLength = parseInt(this.el.getAttribute('maxlength')),
66
95
  actualLength = (this.el as HTMLInputElement).value.length;
67
96
 
68
97
  this.isValidLength = actualLength <= maxLength;
package/src/chips.ts CHANGED
@@ -1,11 +1,80 @@
1
- import { Component } from "./component";
2
- import { M } from "./global";
3
- import { Autocomplete } from "./autocomplete";
1
+ import { Utils } from "./utils";
2
+ import { Autocomplete, AutocompleteOptions } from "./autocomplete";
3
+ import { Component, BaseOptions, InitElements, MElement } from "./component";
4
+
5
+ export interface ChipData {
6
+ /**
7
+ * Unique identifier.
8
+ */
9
+ id: number|string;
10
+ /**
11
+ * Chip text. If not specified, "id" will be used.
12
+ */
13
+ text?: string;
14
+ /**
15
+ * Chip image (URL).
16
+ */
17
+ image?: string;
18
+ }
19
+
20
+ export interface ChipsOptions extends BaseOptions{
21
+ /**
22
+ * Set the chip data.
23
+ * @default []
24
+ */
25
+ data: ChipData[];
26
+ /**
27
+ * Set first placeholder when there are no tags.
28
+ * @default ""
29
+ */
30
+ placeholder: string;
31
+ /**
32
+ * Set second placeholder when adding additional tags.
33
+ * @default ""
34
+ */
35
+ secondaryPlaceholder: string;
36
+ /**
37
+ * Set autocomplete options.
38
+ * @default {}
39
+ */
40
+ autocompleteOptions: Partial<AutocompleteOptions>;
41
+ /**
42
+ * Toggles abililty to add custom value not in autocomplete list.
43
+ * @default false
44
+ */
45
+ autocompleteOnly: boolean;
46
+ /**
47
+ * Set chips limit.
48
+ * @default Infinity
49
+ */
50
+ limit: number;
51
+ /**
52
+ * Specifies class to be used in "close" button (useful when working with Material Symbols icon set).
53
+ * @default 'material-icons'
54
+ */
55
+ closeIconClass: string;
56
+ /**
57
+ * Callback for chip add.
58
+ * @default null
59
+ */
60
+ onChipAdd: (element: HTMLElement, chip: HTMLElement) => void;
61
+ /**
62
+ * Callback for chip select.
63
+ * @default null
64
+ */
65
+ onChipSelect: (element: HTMLElement, chip: HTMLElement) => void;
66
+ /**
67
+ * Callback for chip delete.
68
+ * @default null
69
+ */
70
+ onChipDelete: (element: HTMLElement, chip: HTMLElement) => void;
71
+ }
4
72
 
5
- let _defaults = {
73
+ let _defaults: ChipsOptions = {
6
74
  data: [],
7
75
  placeholder: '',
8
76
  secondaryPlaceholder: '',
77
+ closeIconClass: 'material-icons',
9
78
  autocompleteOptions: {},
10
79
  autocompleteOnly: false,
11
80
  limit: Infinity,
@@ -14,35 +83,31 @@ let _defaults = {
14
83
  onChipDelete: null
15
84
  };
16
85
 
17
- interface DataBit {
18
- id: string, // required
19
- text?: string,
20
- image?: string,
21
- description?: string,
22
- }
23
-
24
86
  function gGetIndex(el: HTMLElement): number {
25
87
  return [...el.parentNode.children].indexOf(el);
26
88
  }
27
89
 
28
- export class Chips extends Component {
29
- chipsData: DataBit[];
90
+ export class Chips extends Component<ChipsOptions> {
91
+ /** Array of the current chips data. */
92
+ chipsData: ChipData[];
93
+ /** If the chips has autocomplete enabled. */
30
94
  hasAutocomplete: boolean;
95
+ /** Autocomplete instance, if any. */
31
96
  autocomplete: Autocomplete;
32
97
  _input: HTMLInputElement;
33
98
  _label: any;
34
99
  _chips: HTMLElement[];
35
- private _handleChipClickBound: any;
36
- private _handleInputKeydownBound: any;
37
- private _handleInputFocusBound: any;
38
- private _handleInputBlurBound: any;
39
100
  static _keydown: boolean;
40
101
  private _selectedChip: any;
41
102
 
42
- constructor(el, options) {
43
- super(Chips, el, options);
103
+ constructor(el: HTMLElement, options: Partial<ChipsOptions>) {
104
+ super(el, options, Chips);
44
105
  (this.el as any).M_Chips = this;
45
- this.options = {...Chips.defaults, ...options};
106
+
107
+ this.options = {
108
+ ...Chips.defaults,
109
+ ...options
110
+ };
46
111
 
47
112
  this.el.classList.add('chips', 'input-field');
48
113
  this.chipsData = [];
@@ -52,7 +117,7 @@ export class Chips extends Component {
52
117
 
53
118
  // Set input id
54
119
  if (!this._input.getAttribute('id'))
55
- this._input.setAttribute('id', M.guid());
120
+ this._input.setAttribute('id', Utils.guid());
56
121
 
57
122
  // Render initial chips
58
123
  if (this.options.data.length) {
@@ -70,13 +135,29 @@ export class Chips extends Component {
70
135
  return _defaults;
71
136
  }
72
137
 
73
- static init(els, options) {
74
- return super.init(this, els, options);
138
+ /**
139
+ * Initializes instance of Chips.
140
+ * @param el HTML element.
141
+ * @param options Component options.
142
+ */
143
+ static init(el: HTMLElement, options?: Partial<ChipsOptions>): Chips;
144
+ /**
145
+ * Initializes instances of Chips.
146
+ * @param els HTML elements.
147
+ * @param options Component options.
148
+ */
149
+ static init(els: InitElements<MElement>, options?: Partial<ChipsOptions>): Chips[];
150
+ /**
151
+ * Initializes instances of Chips.
152
+ * @param els HTML elements.
153
+ * @param options Component options.
154
+ */
155
+ static init(els: HTMLElement | InitElements<MElement>, options: Partial<ChipsOptions> = {}): Chips | Chips[] {
156
+ return super.init(els, options, Chips);
75
157
  }
76
158
 
77
- static getInstance(el) {
78
- const domElem = !!el.jquery ? el[0] : el;
79
- return domElem.M_Chips;
159
+ static getInstance(el: HTMLElement): Chips {
160
+ return (el as any).M_Chips;
80
161
  }
81
162
 
82
163
  getData() {
@@ -91,30 +172,26 @@ export class Chips extends Component {
91
172
  }
92
173
 
93
174
  _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);
175
+ this.el.addEventListener('click', this._handleChipClick);
99
176
  document.addEventListener('keydown', Chips._handleChipsKeydown);
100
177
  document.addEventListener('keyup', Chips._handleChipsKeyup);
101
178
  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);
179
+ this._input.addEventListener('focus', this._handleInputFocus);
180
+ this._input.addEventListener('blur', this._handleInputBlur);
181
+ this._input.addEventListener('keydown', this._handleInputKeydown);
105
182
  }
106
183
 
107
184
  _removeEventHandlers() {
108
- this.el.removeEventListener('click', this._handleChipClickBound);
185
+ this.el.removeEventListener('click', this._handleChipClick);
109
186
  document.removeEventListener('keydown', Chips._handleChipsKeydown);
110
187
  document.removeEventListener('keyup', Chips._handleChipsKeyup);
111
188
  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);
189
+ this._input.removeEventListener('focus', this._handleInputFocus);
190
+ this._input.removeEventListener('blur', this._handleInputBlur);
191
+ this._input.removeEventListener('keydown', this._handleInputKeydown);
115
192
  }
116
193
 
117
- _handleChipClick(e) {
194
+ _handleChipClick = (e: MouseEvent) => {
118
195
  const _chip = (<HTMLElement>e.target).closest('.chip');
119
196
  const clickedClose = (<HTMLElement>e.target).classList.contains('close');
120
197
  if (_chip) {
@@ -133,7 +210,7 @@ export class Chips extends Component {
133
210
  }
134
211
  }
135
212
 
136
- static _handleChipsKeydown(e) {
213
+ static _handleChipsKeydown(e: KeyboardEvent) {
137
214
  Chips._keydown = true;
138
215
  const chips = (<HTMLElement>e.target).closest('.chips');
139
216
  const chipsKeydown = e.target && chips;
@@ -141,10 +218,10 @@ export class Chips extends Component {
141
218
  // Don't handle keydown inputs on input and textarea
142
219
  const tag = (<HTMLElement>e.target).tagName;
143
220
  if (tag === 'INPUT' || tag === 'TEXTAREA' || !chipsKeydown) return;
144
-
221
+
145
222
  const currChips: Chips = (chips as any).M_Chips;
146
- // backspace and delete
147
- if (e.keyCode === 8 || e.keyCode === 46) {
223
+
224
+ if (Utils.keys.BACKSPACE.includes(e.key) || Utils.keys.DELETE.includes(e.key)) {
148
225
  e.preventDefault();
149
226
  let selectIndex = currChips.chipsData.length;
150
227
  if (currChips._selectedChip) {
@@ -159,16 +236,14 @@ export class Chips extends Component {
159
236
  else
160
237
  currChips._input.focus();
161
238
  }
162
- // left arrow key
163
- else if (e.keyCode === 37) {
239
+ else if (Utils.keys.ARROW_LEFT.includes(e.key)) {
164
240
  if (currChips._selectedChip) {
165
241
  const selectIndex = gGetIndex(currChips._selectedChip) - 1;
166
242
  if (selectIndex < 0) return;
167
243
  currChips.selectChip(selectIndex);
168
244
  }
169
245
  }
170
- // right arrow key
171
- else if (e.keyCode === 39) {
246
+ else if (Utils.keys.ARROW_RIGHT.includes(e.key)) {
172
247
  if (currChips._selectedChip) {
173
248
  const selectIndex = gGetIndex(currChips._selectedChip) + 1;
174
249
  if (selectIndex >= currChips.chipsData.length)
@@ -179,11 +254,11 @@ export class Chips extends Component {
179
254
  }
180
255
  }
181
256
 
182
- static _handleChipsKeyup(e) {
257
+ static _handleChipsKeyup(e: Event) {
183
258
  Chips._keydown = false;
184
259
  }
185
260
 
186
- static _handleChipsBlur(e) {
261
+ static _handleChipsBlur(e: Event) {
187
262
  if (!Chips._keydown && document.hidden) {
188
263
  const chips = (<HTMLElement>e.target).closest('.chips');
189
264
  const currChips: Chips = (chips as any).M_Chips;
@@ -191,18 +266,17 @@ export class Chips extends Component {
191
266
  }
192
267
  }
193
268
 
194
- _handleInputFocus() {
269
+ _handleInputFocus = () => {
195
270
  this.el.classList.add('focus');
196
271
  }
197
272
 
198
- _handleInputBlur() {
273
+ _handleInputBlur = () => {
199
274
  this.el.classList.remove('focus');
200
275
  }
201
276
 
202
- _handleInputKeydown(e) {
277
+ _handleInputKeydown = (e: KeyboardEvent) => {
203
278
  Chips._keydown = true;
204
- // enter
205
- if (e.keyCode === 13) {
279
+ if (Utils.keys.ENTER.includes(e.key)) {
206
280
  // Override enter if autocompleting.
207
281
  if (this.hasAutocomplete && this.autocomplete && this.autocomplete.isOpen) {
208
282
  return;
@@ -212,10 +286,9 @@ export class Chips extends Component {
212
286
  this.addChip({id: this._input.value});
213
287
  }
214
288
  this._input.value = '';
215
- // delete or left
216
289
  }
217
- else if (
218
- (e.keyCode === 8 || e.keyCode === 37) &&
290
+ else if (
291
+ (Utils.keys.BACKSPACE.includes(e.key) || Utils.keys.ARROW_LEFT.includes(e.key)) &&
219
292
  this._input.value === '' &&
220
293
  this.chipsData.length
221
294
  ) {
@@ -224,14 +297,14 @@ export class Chips extends Component {
224
297
  }
225
298
  }
226
299
 
227
- _renderChip(chip: DataBit): HTMLDivElement {
300
+ _renderChip(chip: ChipData): HTMLDivElement {
228
301
  if (!chip.id) return;
229
302
  const renderedChip = document.createElement('div');
230
303
  renderedChip.classList.add('chip');
231
- renderedChip.innerText = chip.text || chip.id;
304
+ renderedChip.innerText = chip.text || <string>chip.id;
232
305
  renderedChip.setAttribute('tabindex', "0");
233
306
  const closeIcon = document.createElement('i');
234
- closeIcon.classList.add('material-icons', 'close');
307
+ closeIcon.classList.add(this.options.closeIconClass, 'close');
235
308
  closeIcon.innerText = 'close';
236
309
  // attach image if needed
237
310
  if (chip.image) {
@@ -256,7 +329,11 @@ export class Chips extends Component {
256
329
 
257
330
  _setupAutocomplete() {
258
331
  this.options.autocompleteOptions.onAutocomplete = (items) => {
259
- if (items.length > 0) this.addChip(items[0]);
332
+ if (items.length > 0) this.addChip({
333
+ id: items[0].id,
334
+ text: items[0].text,
335
+ image: items[0].image
336
+ });
260
337
  this._input.value = '';
261
338
  this._input.focus();
262
339
  };
@@ -289,13 +366,17 @@ export class Chips extends Component {
289
366
  }
290
367
  }
291
368
 
292
- _isValidAndNotExist(chip: DataBit) {
369
+ _isValidAndNotExist(chip: ChipData) {
293
370
  const isValid = !!chip.id;
294
371
  const doesNotExist = !this.chipsData.some(item => item.id == chip.id);
295
372
  return isValid && doesNotExist;
296
373
  }
297
374
 
298
- addChip(chip: DataBit) {
375
+ /**
376
+ * Add chip to input.
377
+ * @param chip Chip data object
378
+ */
379
+ addChip(chip: ChipData) {
299
380
  if (!this._isValidAndNotExist(chip) || this.chipsData.length >= this.options.limit) return;
300
381
  const renderedChip = this._renderChip(chip);
301
382
  this._chips.push(renderedChip);
@@ -309,6 +390,10 @@ export class Chips extends Component {
309
390
  }
310
391
  }
311
392
 
393
+ /**
394
+ * Delete nth chip.
395
+ * @param chipIndex Index of chip
396
+ */
312
397
  deleteChip(chipIndex: number) {
313
398
  const chip = this._chips[chipIndex];
314
399
  this._chips[chipIndex].remove();
@@ -321,6 +406,10 @@ export class Chips extends Component {
321
406
  }
322
407
  }
323
408
 
409
+ /**
410
+ * Select nth chip.
411
+ * @param chipIndex Index of chip
412
+ */
324
413
  selectChip(chipIndex: number) {
325
414
  const chip = this._chips[chipIndex];
326
415
  this._selectedChip = chip;
@@ -1,25 +1,68 @@
1
- import { Component } from "./component";
2
1
  import anim from "animejs";
3
2
 
4
- const _defaults = {
3
+ import { Utils } from "./utils";
4
+ import { Component, BaseOptions, InitElements, MElement } from "./component";
5
+
6
+ export interface CollapsibleOptions extends BaseOptions {
7
+ /**
8
+ * If accordion versus collapsible.
9
+ * @default true
10
+ */
11
+ accordion: boolean;
12
+ /**
13
+ * Transition in duration in milliseconds.
14
+ * @default 300
15
+ */
16
+ inDuration: number;
17
+ /**
18
+ * Transition out duration in milliseconds.
19
+ * @default 300
20
+ */
21
+ outDuration: number;
22
+ /**
23
+ * Callback function called before collapsible is opened.
24
+ * @default null
25
+ */
26
+ onOpenStart: (el: Element) => void;
27
+ /**
28
+ * Callback function called after collapsible is opened.
29
+ * @default null
30
+ */
31
+ onOpenEnd: (el: Element) => void;
32
+ /**
33
+ * Callback function called before collapsible is closed.
34
+ * @default null
35
+ */
36
+ onCloseStart: (el: Element) => void;
37
+ /**
38
+ * Callback function called after collapsible is closed.
39
+ * @default null
40
+ */
41
+ onCloseEnd: (el: Element) => void;
42
+ }
43
+
44
+ const _defaults: CollapsibleOptions = {
5
45
  accordion: true,
6
- onOpenStart: undefined,
7
- onOpenEnd: undefined,
8
- onCloseStart: undefined,
9
- onCloseEnd: undefined,
46
+ onOpenStart: null,
47
+ onOpenEnd: null,
48
+ onCloseStart: null,
49
+ onCloseEnd: null,
10
50
  inDuration: 300,
11
51
  outDuration: 300
12
52
  };
13
53
 
14
- export class Collapsible extends Component {
54
+ export class Collapsible extends Component<CollapsibleOptions> {
15
55
  private _headers: HTMLElement[];
16
- private _handleCollapsibleClickBound: any;
17
- private _handleCollapsibleKeydownBound: any;
18
56
 
19
- constructor(el, options) {
20
- super(Collapsible, el, options);
57
+ constructor(el: HTMLElement, options: Partial<CollapsibleOptions>) {
58
+ super(el, options, Collapsible);
21
59
  (this.el as any).M_Collapsible = this;
22
- this.options = {...Collapsible.defaults, ...options};
60
+
61
+ this.options = {
62
+ ...Collapsible.defaults,
63
+ ...options
64
+ };
65
+
23
66
  // Setup tab indices
24
67
  this._headers = Array.from(this.el.querySelectorAll('li > .collapsible-header'));
25
68
  this._headers.forEach(el => el.tabIndex = 0);
@@ -29,21 +72,37 @@ export class Collapsible extends Component {
29
72
  if (this.options.accordion)
30
73
  if (activeBodies.length > 0)
31
74
  activeBodies[0].style.display = 'block'; // Accordion
32
- else
75
+ else
33
76
  activeBodies.forEach(el => el.style.display = 'block'); // Expandables
34
77
  }
35
78
 
36
- static get defaults() {
79
+ static get defaults(): CollapsibleOptions {
37
80
  return _defaults;
38
81
  }
39
82
 
40
- static init(els, options) {
41
- return super.init(this, els, options);
83
+ /**
84
+ * Initializes instance of Collapsible.
85
+ * @param el HTML element.
86
+ * @param options Component options.
87
+ */
88
+ static init(el: HTMLElement, options?: Partial<CollapsibleOptions>): Collapsible;
89
+ /**
90
+ * Initializes instances of Collapsible.
91
+ * @param els HTML elements.
92
+ * @param options Component options.
93
+ */
94
+ static init(els: InitElements<MElement>, options?: Partial<CollapsibleOptions>): Collapsible[];
95
+ /**
96
+ * Initializes instances of Collapsible.
97
+ * @param els HTML elements.
98
+ * @param options Component options.
99
+ */
100
+ static init(els: HTMLElement | InitElements<MElement>, options: Partial<CollapsibleOptions> = {}): Collapsible | Collapsible[] {
101
+ return super.init(els, options, Collapsible);
42
102
  }
43
103
 
44
- static getInstance(el) {
45
- const domElem = !!el.jquery ? el[0] : el;
46
- return domElem.M_Collapsible;
104
+ static getInstance(el: HTMLElement): Collapsible {
105
+ return (el as any).M_Collapsible;
47
106
  }
48
107
 
49
108
  destroy() {
@@ -52,19 +111,17 @@ export class Collapsible extends Component {
52
111
  }
53
112
 
54
113
  _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));
114
+ this.el.addEventListener('click', this._handleCollapsibleClick);
115
+ this._headers.forEach(header => header.addEventListener('keydown', this._handleCollapsibleKeydown));
59
116
  }
60
117
 
61
118
  _removeEventHandlers() {
62
- this.el.removeEventListener('click', this._handleCollapsibleClickBound);
63
- this._headers.forEach(header => header.removeEventListener('keydown', this._handleCollapsibleKeydownBound));
119
+ this.el.removeEventListener('click', this._handleCollapsibleClick);
120
+ this._headers.forEach(header => header.removeEventListener('keydown', this._handleCollapsibleKeydown));
64
121
  }
65
122
 
66
- _handleCollapsibleClick(e) {
67
- const header = e.target.closest('.collapsible-header');
123
+ _handleCollapsibleClick = (e: MouseEvent | KeyboardEvent) => {
124
+ const header = (e.target as HTMLElement).closest('.collapsible-header');
68
125
  if (e.target && header) {
69
126
  const collapsible = header.closest('.collapsible');
70
127
  if (collapsible !== this.el) return;
@@ -80,9 +137,9 @@ export class Collapsible extends Component {
80
137
  }
81
138
  }
82
139
 
83
- _handleCollapsibleKeydown(e) {
84
- if (e.keyCode === 13) {
85
- this._handleCollapsibleClickBound(e);
140
+ _handleCollapsibleKeydown = (e: KeyboardEvent) => {
141
+ if (Utils.keys.ENTER.includes(e.key)) {
142
+ this._handleCollapsibleClick(e);
86
143
  }
87
144
  }
88
145
 
@@ -147,7 +204,11 @@ export class Collapsible extends Component {
147
204
  });
148
205
  }
149
206
 
150
- open(index: number) {
207
+ /**
208
+ * Open collapsible section.
209
+ * @param n Nth section to open.
210
+ */
211
+ open = (index: number) => {
151
212
  const listItems = Array.from(this.el.children).filter(c => c.tagName === 'LI');
152
213
  const li = listItems[index];
153
214
  if (li && !li.classList.contains('active')) {
@@ -169,7 +230,11 @@ export class Collapsible extends Component {
169
230
  }
170
231
  }
171
232
 
172
- close(index: number) {
233
+ /**
234
+ * Close collapsible section.
235
+ * @param n Nth section to close.
236
+ */
237
+ close = (index: number) => {
173
238
  const li = Array.from(this.el.children).filter(c => c.tagName === 'LI')[index];
174
239
  if (li && li.classList.contains('active')) {
175
240
  // onCloseStart callback