kmaterialize 2.0.0 → 2.3.3-1.0.1

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 (156) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +55 -91
  3. package/components/appbar/_navbar.old.scss +223 -0
  4. package/components/appbar/appbar.css +235 -0
  5. package/components/appbar/appbar.mjs +54 -0
  6. package/components/appbar/appbar.test.mjs +9 -0
  7. package/components/atomic/atomic.mjs +19 -0
  8. package/components/atomic/component.mjs +67 -0
  9. package/components/badge/_badges.scss +75 -0
  10. package/components/badge/badge.mjs +11 -0
  11. package/components/breadcrumb/_breadcrumb.scss +27 -0
  12. package/components/button/_buttons.scss +352 -0
  13. package/components/button/button.mjs +11 -0
  14. package/components/button/buttons.stories.ts +150 -0
  15. package/components/button/buttons.ts +282 -0
  16. package/components/button/examples.iso.js +18 -0
  17. package/components/button/fabSpec.js +65 -0
  18. package/components/button/test-button.mjs +16 -0
  19. package/components/card/_cards.scss +229 -0
  20. package/components/card/card.mjs +10 -0
  21. package/components/card/cards.ts +185 -0
  22. package/components/card/cardsSpec.js +269 -0
  23. package/components/carousel/_carousel.scss +93 -0
  24. package/components/carousel/_slider.scss +119 -0
  25. package/components/carousel/carousel.ts +693 -0
  26. package/components/carousel/carouselSpec.js +61 -0
  27. package/components/carousel/slider.ts +431 -0
  28. package/components/carousel/sliderSpec.js +99 -0
  29. package/components/checkbox/_checkboxes.scss +281 -0
  30. package/components/checkbox/checkbox.mdx +24 -0
  31. package/components/checkbox/checkbox.stories.ts +120 -0
  32. package/components/chip/chip.mjs +37 -0
  33. package/components/chip/chip.test.mjs +10 -0
  34. package/components/chip/chips.css +126 -0
  35. package/components/chip/chips.mdx +33 -0
  36. package/components/chip/chips.ts +440 -0
  37. package/components/chip/chipsSpec.js +165 -0
  38. package/components/chip/readme.md +323 -0
  39. package/components/collapsible/_collapsible.scss +82 -0
  40. package/components/collapsible/collapsible.ts +230 -0
  41. package/components/collapsible/collapsibleSpec.js +240 -0
  42. package/components/datepicker/_datepicker.scss +268 -0
  43. package/components/datepicker/datepicker.ts +1450 -0
  44. package/components/datepicker/datepickerSpec.js +162 -0
  45. package/components/dialog/_materialbox.scss +42 -0
  46. package/components/dialog/_modal.scss +79 -0
  47. package/components/dialog/materialbox.ts +446 -0
  48. package/components/dialog/materialboxSpec.js +37 -0
  49. package/components/dialog/modal.ts +111 -0
  50. package/components/dialog/modalSpec.js +83 -0
  51. package/components/dialog/readme.md +5 -0
  52. package/components/divider/readme.md +15 -0
  53. package/components/dropdown/_dropdown.scss +83 -0
  54. package/components/dropdown/dropdown.ts +653 -0
  55. package/components/dropdown/dropdownSpec.js +108 -0
  56. package/components/list/_collection.scss +114 -0
  57. package/components/list/_list.scss +6 -0
  58. package/components/list/list.mjs +58 -0
  59. package/components/list/list.test.mjs +16 -0
  60. package/components/loading/loading.mjs +26 -0
  61. package/components/loading/loading.test.mjs +10 -0
  62. package/components/navigation-bar/_old +582 -0
  63. package/components/navigation-bar/navigation-bar.mdx +20 -0
  64. package/components/navigation-bar/navigation-bar.stories.ts +39 -0
  65. package/components/navigation-drawer/_sidenav.scss +247 -0
  66. package/components/navigation-drawer/sidenav.ts +546 -0
  67. package/components/navigation-drawer/sidenavSpec.js +124 -0
  68. package/components/pagination/_pagination.scss +47 -0
  69. package/components/progress/_preloader.scss +416 -0
  70. package/components/radio-button/_radio-buttons.scss +112 -0
  71. package/components/radio-button/radio-buttons.mdx +28 -0
  72. package/components/radio-button/radio-buttons.stories.ts +51 -0
  73. package/components/search/autocomplete.ts +620 -0
  74. package/components/search/autocompleteSpec.js +321 -0
  75. package/components/slider/_range.scss +157 -0
  76. package/components/slider/range.ts +216 -0
  77. package/components/snackbar/_toast.scss +68 -0
  78. package/components/snackbar/toastSpec.js +132 -0
  79. package/components/snackbar/toasts.ts +312 -0
  80. package/components/switch/_switches.scss +121 -0
  81. package/components/tabs/_tabs.scss +171 -0
  82. package/components/tabs/tabs.mjs +31 -0
  83. package/components/tabs/tabs.ts +358 -0
  84. package/components/tabs/tabsSpec.js +180 -0
  85. package/components/textfield/_file-input.scss +41 -0
  86. package/components/textfield/_input-fields.scss +368 -0
  87. package/components/textfield/_select.scss +104 -0
  88. package/components/textfield/formfields.css +311 -0
  89. package/components/textfield/forms.ts +182 -0
  90. package/components/textfield/formsSpec.js +142 -0
  91. package/components/textfield/select.ts +472 -0
  92. package/components/textfield/selectSpec.js +390 -0
  93. package/components/textfield/textfield.mjs +29 -0
  94. package/components/textfield/textfield.test.mjs +10 -0
  95. package/components/timepicker/_timepicker.scss +362 -0
  96. package/components/timepicker/timepicker.ts +905 -0
  97. package/components/tooltip/_tooltip.scss +40 -0
  98. package/components/tooltip/tooltip.ts +380 -0
  99. package/components/tooltip/tooltipSpec.js +145 -0
  100. package/dist/css/materialize.colors.min.css +6 -0
  101. package/dist/css/materialize.css +7578 -6326
  102. package/dist/css/materialize.min.css +6 -13
  103. package/dist/css/materialize.min.css.map +1 -0
  104. package/dist/js/materialize.cjs.js +8410 -0
  105. package/dist/js/materialize.d.ts +2625 -0
  106. package/dist/js/materialize.js +8415 -12374
  107. package/dist/js/materialize.min.js +6 -6
  108. package/dist/js/materialize.mjs +8382 -0
  109. package/package.json +82 -47
  110. package/sass/_colors.scss +417 -0
  111. package/sass/_global.scss +490 -0
  112. package/sass/_grid.scss +172 -0
  113. package/sass/_table_of_contents.scss +28 -0
  114. package/sass/_tapTarget.scss +102 -0
  115. package/sass/_typography.scss +58 -0
  116. package/sass/_variables.scss +56 -0
  117. package/sass/colors.module.css +74 -0
  118. package/sass/materialize.scss +51 -0
  119. package/sass/mixins.module.scss +168 -0
  120. package/sass/pulse.css +35 -0
  121. package/sass/theme.module.css +140 -0
  122. package/sass/tokens.module.css +272 -0
  123. package/sass/transitions.css +10 -0
  124. package/sass/typography.module.css +150 -0
  125. package/extras/noUiSlider/nouislider.css +0 -406
  126. package/extras/noUiSlider/nouislider.js +0 -2147
  127. package/extras/noUiSlider/nouislider.min.js +0 -1
  128. package/js/anime.min.js +0 -34
  129. package/js/autocomplete.js +0 -448
  130. package/js/buttons.js +0 -354
  131. package/js/cards.js +0 -40
  132. package/js/carousel.js +0 -717
  133. package/js/cash.js +0 -960
  134. package/js/characterCounter.js +0 -136
  135. package/js/chips.js +0 -481
  136. package/js/collapsible.js +0 -275
  137. package/js/component.js +0 -44
  138. package/js/datepicker.js +0 -975
  139. package/js/dropdown.js +0 -635
  140. package/js/forms.js +0 -275
  141. package/js/global.js +0 -444
  142. package/js/materialbox.js +0 -453
  143. package/js/modal.js +0 -382
  144. package/js/parallax.js +0 -138
  145. package/js/pushpin.js +0 -148
  146. package/js/range.js +0 -263
  147. package/js/scrollspy.js +0 -295
  148. package/js/select.js +0 -450
  149. package/js/sidenav.js +0 -580
  150. package/js/slider.js +0 -359
  151. package/js/tabs.js +0 -402
  152. package/js/tapTarget.js +0 -314
  153. package/js/timepicker.js +0 -647
  154. package/js/toasts.js +0 -310
  155. package/js/tooltip.js +0 -303
  156. package/js/waves.js +0 -335
@@ -0,0 +1,472 @@
1
+ import { Utils } from '../../src/utils';
2
+ import { Dropdown, DropdownOptions } from '../dropdown/dropdown';
3
+ import { Component, BaseOptions, InitElements, MElement } from '../../src/component';
4
+
5
+ export interface FormSelectOptions extends BaseOptions {
6
+ /**
7
+ * Classes to be added to the select wrapper element.
8
+ * @default ""
9
+ */
10
+ classes: string;
11
+ /**
12
+ * Pass options object to select dropdown initialization.
13
+ * @default {}
14
+ */
15
+ dropdownOptions: Partial<DropdownOptions>;
16
+ }
17
+
18
+ const _defaults: FormSelectOptions = {
19
+ classes: '',
20
+ dropdownOptions: {}
21
+ };
22
+
23
+ type ValueStruct = {
24
+ el: HTMLOptionElement;
25
+ optionEl: HTMLElement;
26
+ };
27
+
28
+ export class FormSelect extends Component<FormSelectOptions> {
29
+ declare el: HTMLSelectElement;
30
+ /** If this is a multiple select. */
31
+ isMultiple: boolean;
32
+ /**
33
+ * Label associated with the current select element.
34
+ * Is "null", if not detected.
35
+ */
36
+ labelEl: HTMLLabelElement;
37
+ /** Dropdown UL element. */
38
+ dropdownOptions: HTMLUListElement;
39
+ /** Text input that shows current selected option. */
40
+ input: HTMLInputElement;
41
+ /** Instance of the dropdown plugin for this select. */
42
+ dropdown: Dropdown;
43
+ /** The select wrapper element. */
44
+ wrapper: HTMLDivElement;
45
+ selectOptions: (HTMLOptionElement | HTMLOptGroupElement)[];
46
+ private _values: ValueStruct[];
47
+ nativeTabIndex: number;
48
+
49
+ constructor(el: HTMLSelectElement, options: FormSelectOptions) {
50
+ super(el, options, FormSelect);
51
+ if (this.el.classList.contains('browser-default')) return;
52
+ this.el['M_FormSelect'] = this;
53
+
54
+ this.options = {
55
+ ...FormSelect.defaults,
56
+ ...options
57
+ };
58
+
59
+ this.isMultiple = this.el.multiple;
60
+ this.nativeTabIndex = this.el.tabIndex ?? -1;
61
+ this.el.tabIndex = -1;
62
+ this._values = [];
63
+ this._setupDropdown();
64
+ this._setupEventHandlers();
65
+ }
66
+
67
+ static get defaults(): FormSelectOptions {
68
+ return _defaults;
69
+ }
70
+
71
+ /**
72
+ * Initializes instance of FormSelect.
73
+ * @param el HTML element.
74
+ * @param options Component options.
75
+ */
76
+ static init(el: HTMLSelectElement, options?: Partial<FormSelectOptions>): FormSelect;
77
+ /**
78
+ * Initializes instances of FormSelect.
79
+ * @param els HTML elements.
80
+ * @param options Component options.
81
+ */
82
+ static init(
83
+ els: InitElements<HTMLSelectElement | MElement>,
84
+ options?: Partial<FormSelectOptions>
85
+ ): FormSelect[];
86
+ /**
87
+ * Initializes instances of FormSelect.
88
+ * @param els HTML elements.
89
+ * @param options Component options.
90
+ */
91
+ static init(
92
+ els: HTMLSelectElement | InitElements<HTMLSelectElement | MElement>,
93
+ options: Partial<FormSelectOptions> = {}
94
+ ): FormSelect | FormSelect[] {
95
+ return super.init(els, options, FormSelect);
96
+ }
97
+
98
+ static getInstance(el: HTMLElement): FormSelect {
99
+ return el['M_FormSelect'];
100
+ }
101
+
102
+ destroy() {
103
+ this._removeEventHandlers();
104
+ this._removeDropdown();
105
+ this.el['M_FormSelect'] = undefined;
106
+ }
107
+
108
+ _setupEventHandlers() {
109
+ this.dropdownOptions.querySelectorAll('li:not(.optgroup)').forEach((el) => {
110
+ el.addEventListener('click', this._handleOptionClick);
111
+ el.addEventListener('keydown', (e: KeyboardEvent) => {
112
+ if (e.key === ' ' || e.key === 'Enter') this._handleOptionClick(e);
113
+ });
114
+ });
115
+ this.el.addEventListener('change', this._handleSelectChange);
116
+ this.input.addEventListener('click', this._handleInputClick);
117
+ }
118
+
119
+ _removeEventHandlers() {
120
+ this.dropdownOptions.querySelectorAll('li:not(.optgroup)').forEach((el) => {
121
+ el.removeEventListener('click', this._handleOptionClick);
122
+ });
123
+ this.el.removeEventListener('change', this._handleSelectChange);
124
+ this.input.removeEventListener('click', this._handleInputClick);
125
+ }
126
+
127
+ _handleSelectChange = () => {
128
+ this._setValueToInput();
129
+ };
130
+
131
+ _handleOptionClick = (e: MouseEvent | KeyboardEvent) => {
132
+ e.preventDefault();
133
+ const virtualOption = (e.target as HTMLLIElement).closest('li');
134
+ this._selectOptionElement(virtualOption);
135
+ e.stopPropagation();
136
+ };
137
+
138
+ _arraysEqual<T, E>(a: T[], b: (E | T)[]) {
139
+ if (a === b) return true;
140
+ if (a == null || b == null) return false;
141
+ if (a.length !== b.length) return false;
142
+ for (let i = 0; i < a.length; ++i) if (a[i] !== b[i]) return false;
143
+ return true;
144
+ }
145
+
146
+ _selectOptionElement(virtualOption: HTMLElement) {
147
+ if (
148
+ !virtualOption.classList.contains('disabled') &&
149
+ !virtualOption.classList.contains('optgroup')
150
+ ) {
151
+ const value = this._values.find((value) => value.optionEl === virtualOption);
152
+ const previousSelectedValues = this.getSelectedValues();
153
+ if (this.isMultiple) {
154
+ // Multi-Select
155
+ this._toggleEntryFromArray(value);
156
+ } else {
157
+ // Single-Select
158
+ this._deselectAll();
159
+ this._selectValue(value);
160
+ }
161
+ // Refresh Input-Text
162
+ this._setValueToInput();
163
+ // Trigger Change-Event only when data is different
164
+ const actualSelectedValues = this.getSelectedValues();
165
+ const selectionHasChanged = !this._arraysEqual(previousSelectedValues, actualSelectedValues);
166
+ if (selectionHasChanged)
167
+ this.el.dispatchEvent(
168
+ new Event('change', { bubbles: true, cancelable: true, composed: true })
169
+ ); // trigger('change');
170
+ }
171
+ if (!this.isMultiple) this.dropdown.close();
172
+ }
173
+
174
+ _handleInputClick = () => {
175
+ if (this.dropdown && this.dropdown.isOpen) {
176
+ this._setValueToInput();
177
+ this._setSelectedStates();
178
+ }
179
+ };
180
+
181
+ _setupDropdown() {
182
+ this.labelEl = document.querySelector('[for="' + this.el.id + '"]');
183
+
184
+ this.wrapper = document.createElement('div');
185
+ this.wrapper.classList.add('select-wrapper', 'input-field');
186
+ if (this.options.classes.length > 0) {
187
+ this.wrapper.classList.add(...this.options.classes.split(' '));
188
+ }
189
+ this.el.before(this.wrapper);
190
+
191
+ // Move actual select element into overflow hidden wrapper
192
+ const hiddenDiv = document.createElement('div');
193
+ hiddenDiv.classList.add('hide-select');
194
+ this.wrapper.append(hiddenDiv);
195
+ hiddenDiv.appendChild(this.el);
196
+
197
+ if (this.el.disabled) this.wrapper.classList.add('disabled');
198
+
199
+ this.selectOptions = <(HTMLOptGroupElement | HTMLOptionElement)[]>(
200
+ Array.from(this.el.children).filter((el) => ['OPTION', 'OPTGROUP'].includes(el.tagName))
201
+ );
202
+
203
+ // Create dropdown
204
+ this.dropdownOptions = document.createElement('ul');
205
+ this.dropdownOptions.id = `select-options-${Utils.guid()}`;
206
+ this.dropdownOptions.setAttribute('popover', 'auto');
207
+ this.dropdownOptions.classList.add('dropdown-content', 'select-dropdown');
208
+ this.dropdownOptions.setAttribute('role', 'listbox');
209
+ this.dropdownOptions.ariaMultiSelectable = this.isMultiple.toString();
210
+ if (this.isMultiple) this.dropdownOptions.classList.add('multiple-select-dropdown');
211
+
212
+ // Create dropdown structure
213
+ if (this.selectOptions.length > 0) {
214
+ this.selectOptions.forEach((realOption) => {
215
+ if (realOption.tagName === 'OPTION') {
216
+ // Option
217
+ const virtualOption = this._createAndAppendOptionWithIcon(
218
+ realOption,
219
+ this.isMultiple ? 'multiple' : undefined
220
+ );
221
+ this._addOptionToValues(realOption as HTMLOptionElement, virtualOption);
222
+ } else if (realOption.tagName === 'OPTGROUP') {
223
+ // Optgroup
224
+ const groupId = 'opt-group-' + Utils.guid();
225
+ const groupParent = document.createElement('li');
226
+ groupParent.classList.add('optgroup');
227
+ groupParent.tabIndex = -1;
228
+ groupParent.setAttribute('role', 'group');
229
+ groupParent.setAttribute('aria-labelledby', groupId);
230
+ groupParent.innerHTML = `<span id="${groupId}" role="presentation">${realOption.getAttribute(
231
+ 'label'
232
+ )}</span>`;
233
+ this.dropdownOptions.append(groupParent);
234
+
235
+ const groupChildren = [];
236
+ const selectOptions = <HTMLOptionElement[]>(
237
+ Array.from(realOption.children).filter((el) => el.tagName === 'OPTION')
238
+ );
239
+ selectOptions.forEach((realOption) => {
240
+ const virtualOption = this._createAndAppendOptionWithIcon(
241
+ realOption,
242
+ 'optgroup-option'
243
+ );
244
+ const childId = 'opt-child-' + Utils.guid();
245
+ virtualOption.id = childId;
246
+ groupChildren.push(childId);
247
+ this._addOptionToValues(realOption, virtualOption);
248
+ });
249
+ groupParent.setAttribute('aria-owns', groupChildren.join(' '));
250
+ }
251
+ });
252
+ }
253
+ this.wrapper.append(this.dropdownOptions);
254
+
255
+ // Add input dropdown
256
+ this.input = document.createElement('input');
257
+ this.input.id = 'm_select-input-' + Utils.guid();
258
+ this.input.classList.add('select-dropdown', 'dropdown-trigger');
259
+ this.input.type = 'text';
260
+ this.input.readOnly = true;
261
+ this.input.setAttribute('data-target', this.dropdownOptions.id);
262
+ this.input.ariaReadOnly = 'true';
263
+ this.input.ariaRequired = this.el.hasAttribute('required').toString(); //setAttribute("aria-required", this.el.hasAttribute("required"));
264
+ if (this.el.disabled) this.input.disabled = true; // 'true');
265
+ this.input.setAttribute('tabindex', this.nativeTabIndex.toString());
266
+
267
+ const attrs = this.el.attributes;
268
+ for (let i = 0; i < attrs.length; ++i) {
269
+ const attr = attrs[i];
270
+ if (attr.name.startsWith('aria-')) this.input.setAttribute(attr.name, attr.value);
271
+ }
272
+
273
+ // Adds aria-attributes to input element
274
+ this.input.setAttribute('role', 'combobox');
275
+ this.input.ariaExpanded = 'false';
276
+ this.input.setAttribute('aria-owns', this.dropdownOptions.id);
277
+ this.input.setAttribute('aria-controls', this.dropdownOptions.id);
278
+ this.input.placeholder = ' ';
279
+
280
+ this.wrapper.prepend(this.input);
281
+ this._setValueToInput();
282
+
283
+ // Add caret
284
+ const dropdownIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); //document.createElement('svg')
285
+ dropdownIcon.classList.add('caret');
286
+ dropdownIcon.setAttribute('height', '24');
287
+ dropdownIcon.setAttribute('width', '24');
288
+ dropdownIcon.setAttribute('viewBox', '0 0 24 24');
289
+ dropdownIcon.ariaHidden = 'true';
290
+ dropdownIcon.innerHTML = `<path d="M7 10l5 5 5-5z"/><path d="M0 0h24v24H0z" fill="none"/>`;
291
+ this.wrapper.prepend(dropdownIcon);
292
+
293
+ // Initialize dropdown
294
+ if (!this.el.disabled) {
295
+ const dropdownOptions = { ...this.options.dropdownOptions };
296
+ dropdownOptions.coverTrigger = false;
297
+ const userOnOpenEnd = dropdownOptions.onOpenEnd;
298
+ const userOnCloseEnd = dropdownOptions.onCloseEnd;
299
+ // Add callback for centering selected option when dropdown content is scrollable
300
+ dropdownOptions.onOpenEnd = () => {
301
+ const selectedOption = this.dropdownOptions.querySelector('.selected');
302
+ if (selectedOption) {
303
+ // Focus selected option in dropdown
304
+ Utils.keyDown = true;
305
+ this.dropdown.focusedIndex = [...selectedOption.parentNode.children].indexOf(
306
+ selectedOption
307
+ );
308
+ this.dropdown._focusFocusedItem();
309
+ Utils.keyDown = false;
310
+ // Handle scrolling to selected option
311
+ if (this.dropdown.isScrollable) {
312
+ let scrollOffset =
313
+ selectedOption.getBoundingClientRect().top -
314
+ (this.dropdownOptions as HTMLElement).getBoundingClientRect().top; // scroll to selected option
315
+ scrollOffset -= this.dropdownOptions.clientHeight / 2; // center in dropdown
316
+ this.dropdownOptions.scrollTop = scrollOffset;
317
+ }
318
+ }
319
+ this.input.ariaExpanded = 'true';
320
+ // Handle user declared onOpenEnd if needed
321
+ if (userOnOpenEnd && typeof userOnOpenEnd === 'function')
322
+ userOnOpenEnd.call(this.dropdown, this.el);
323
+ };
324
+ // Add callback for reseting "expanded" state
325
+ dropdownOptions.onCloseEnd = () => {
326
+ this.input.ariaExpanded = 'false';
327
+ // Handle user declared onOpenEnd if needed
328
+ if (userOnCloseEnd && typeof userOnCloseEnd === 'function')
329
+ userOnCloseEnd.call(this.dropdown, this.el);
330
+ };
331
+ // Prevent dropdown from closing too early
332
+ dropdownOptions.closeOnClick = false;
333
+ this.dropdown = Dropdown.init(this.input, dropdownOptions);
334
+ }
335
+ // Add initial selections
336
+ this._setSelectedStates();
337
+ // move label
338
+ if (this.labelEl) this.input.after(this.labelEl);
339
+ }
340
+
341
+ _addOptionToValues(realOption: HTMLOptionElement, virtualOption: HTMLElement) {
342
+ this._values.push({ el: realOption, optionEl: virtualOption });
343
+ }
344
+
345
+ _removeDropdown() {
346
+ this.wrapper.querySelector('.caret').remove();
347
+ this.input.remove();
348
+ this.dropdownOptions.remove();
349
+ this.wrapper.before(this.el);
350
+ this.wrapper.remove();
351
+ }
352
+
353
+ _createAndAppendOptionWithIcon(
354
+ realOption: HTMLOptionElement | HTMLOptGroupElement,
355
+ type: string
356
+ ) {
357
+ const li = document.createElement('li');
358
+ li.setAttribute('role', 'option');
359
+ if (realOption.disabled) {
360
+ li.classList.add('disabled');
361
+ li.ariaDisabled = 'true';
362
+ }
363
+ if (type === 'optgroup-option') li.classList.add(type);
364
+
365
+ // Text / Checkbox
366
+ const span = document.createElement('span');
367
+ span.innerHTML = realOption.innerHTML;
368
+ if (this.isMultiple && !realOption.disabled) {
369
+ span.innerHTML = `<label><input type="checkbox"><span>${realOption.innerHTML}</span></label>`;
370
+ }
371
+ li.appendChild(span);
372
+
373
+ // add Icon
374
+ const iconUrl = realOption.getAttribute('data-icon');
375
+ const classes = realOption.getAttribute('class')?.split(' ');
376
+ if (iconUrl) {
377
+ const img = document.createElement('img');
378
+ if (classes) img.classList.add(...classes);
379
+ img.src = iconUrl;
380
+ img.ariaHidden = 'true';
381
+ li.prepend(img);
382
+ }
383
+ // Check for multiple type
384
+ this.dropdownOptions.append(li);
385
+ return li;
386
+ }
387
+
388
+ _selectValue(value: ValueStruct) {
389
+ value.el.selected = true;
390
+ value.optionEl.classList.add('selected');
391
+ value.optionEl.ariaSelected = 'true'; // setAttribute("aria-selected", true);
392
+ const checkbox = <HTMLInputElement>value.optionEl.querySelector('input[type="checkbox"]');
393
+ if (checkbox) checkbox.checked = true;
394
+ }
395
+
396
+ _deselectValue(value: ValueStruct) {
397
+ value.el.selected = false;
398
+ value.optionEl.classList.remove('selected');
399
+ value.optionEl.ariaSelected = 'false'; //setAttribute("aria-selected", false);
400
+ const checkbox = <HTMLInputElement>value.optionEl.querySelector('input[type="checkbox"]');
401
+ if (checkbox) checkbox.checked = false;
402
+ }
403
+
404
+ _deselectAll() {
405
+ this._values.forEach((value) => this._deselectValue(value));
406
+ }
407
+
408
+ _isValueSelected(value: ValueStruct) {
409
+ const realValues = this.getSelectedValues();
410
+ return realValues.some((realValue) => realValue === value.el.value);
411
+ }
412
+
413
+ _toggleEntryFromArray(value: ValueStruct) {
414
+ if (this._isValueSelected(value)) this._deselectValue(value);
415
+ else this._selectValue(value);
416
+ }
417
+
418
+ _getSelectedOptions(): HTMLOptionElement[] {
419
+ // remove null, false, ... values
420
+ return Array.prototype.filter.call(
421
+ this.el.selectedOptions,
422
+ (realOption: HTMLOptionElement) => realOption
423
+ );
424
+ }
425
+
426
+ _setValueToInput() {
427
+ const selectedRealOptions = this._getSelectedOptions();
428
+ const selectedOptionPairs = this._values.filter(
429
+ (value) => selectedRealOptions.indexOf(value.el) >= 0
430
+ );
431
+ // Filter not disabled
432
+ const notDisabledOptionPairs = selectedOptionPairs.filter((op) => !op.el.disabled);
433
+ const texts = notDisabledOptionPairs.map((value) =>
434
+ value.optionEl.querySelector('span').innerText.trim()
435
+ );
436
+ // Set input-text to first Option with empty value which indicates a description like "choose your option"
437
+ if (texts.length === 0) {
438
+ const firstDisabledOption = <HTMLOptionElement>this.el.querySelector('option:disabled');
439
+ if (firstDisabledOption && firstDisabledOption.value === '') {
440
+ this.input.value = firstDisabledOption.innerText;
441
+ return;
442
+ }
443
+ }
444
+ this.input.value = texts.join(', ');
445
+ }
446
+
447
+ _setSelectedStates() {
448
+ this._values.forEach((value) => {
449
+ const optionIsSelected = value.el.selected;
450
+ const cb = <HTMLInputElement>value.optionEl.querySelector('input[type="checkbox"]');
451
+ if (cb) cb.checked = optionIsSelected;
452
+ if (optionIsSelected) {
453
+ this._activateOption(this.dropdownOptions, value.optionEl);
454
+ } else {
455
+ value.optionEl.classList.remove('selected');
456
+ value.optionEl.ariaSelected = 'false'; // attr("aria-selected", 'false');
457
+ }
458
+ });
459
+ }
460
+
461
+ _activateOption(ul: HTMLElement, li: HTMLElement) {
462
+ if (!li) return;
463
+ if (!this.isMultiple)
464
+ ul.querySelectorAll('li.selected').forEach((li) => li.classList.remove('selected'));
465
+ li.classList.add('selected');
466
+ li.ariaSelected = 'true';
467
+ }
468
+
469
+ getSelectedValues() {
470
+ return this._getSelectedOptions().map((realOption) => realOption.value);
471
+ }
472
+ }