@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.
Files changed (90) hide show
  1. package/Gruntfile.js +68 -313
  2. package/README.md +26 -14
  3. package/dist/css/materialize.css +1009 -1822
  4. package/dist/css/materialize.min.css +2 -8
  5. package/dist/js/materialize.js +8414 -12299
  6. package/dist/js/materialize.min.js +8968 -2
  7. package/dist/js/materialize.min.js.map +1 -0
  8. package/package.json +13 -9
  9. package/sass/components/_badges.scss +12 -2
  10. package/sass/components/_buttons.scss +16 -11
  11. package/sass/components/_cards.scss +14 -9
  12. package/sass/components/_carousel.scss +5 -2
  13. package/sass/components/_chips.scss +3 -3
  14. package/sass/components/_collapsible.scss +22 -8
  15. package/sass/components/_collection.scss +14 -6
  16. package/sass/components/_datepicker.scss +30 -11
  17. package/sass/components/_dropdown.scss +6 -4
  18. package/sass/components/_global.scss +132 -111
  19. package/sass/components/_grid.scss +119 -98
  20. package/sass/components/_modal.scss +3 -3
  21. package/sass/components/_navbar.scss +31 -17
  22. package/sass/components/_normalize.scss +26 -124
  23. package/sass/components/_sidenav.scss +21 -20
  24. package/sass/components/_slider.scss +27 -7
  25. package/sass/components/_table_of_contents.scss +12 -12
  26. package/sass/components/_tabs.scss +47 -16
  27. package/sass/components/_tapTarget.scss +6 -6
  28. package/sass/components/_theme_variables.scss +98 -0
  29. package/sass/components/_timepicker.scss +54 -46
  30. package/sass/components/_toast.scss +3 -3
  31. package/sass/components/_tooltip.scss +4 -5
  32. package/sass/components/_typography.scss +1 -1
  33. package/sass/components/_variables.scss +185 -120
  34. package/sass/components/forms/_checkboxes.scss +9 -9
  35. package/sass/components/forms/_file-input.scss +9 -7
  36. package/sass/components/forms/_input-fields.scss +173 -234
  37. package/sass/components/forms/_radio-buttons.scss +1 -1
  38. package/sass/components/forms/_range.scss +11 -11
  39. package/sass/components/forms/_select.scss +29 -19
  40. package/sass/components/forms/_switches.scss +22 -18
  41. package/sass/materialize.scss +1 -1
  42. package/src/autocomplete.ts +459 -0
  43. package/src/bounding.ts +6 -0
  44. package/{js/buttons.js → src/buttons.ts} +103 -162
  45. package/src/cards.ts +54 -0
  46. package/{js/carousel.js → src/carousel.ts} +137 -262
  47. package/src/characterCounter.ts +88 -0
  48. package/src/chips.ts +350 -0
  49. package/src/collapsible.ts +184 -0
  50. package/{js/component.js → src/component.ts} +6 -19
  51. package/{js/datepicker.js → src/datepicker.ts} +213 -299
  52. package/{js/dropdown.js → src/dropdown.ts} +140 -254
  53. package/src/edges.ts +6 -0
  54. package/src/forms.ts +120 -0
  55. package/src/global.ts +385 -0
  56. package/src/materialbox.ts +348 -0
  57. package/src/modal.ts +256 -0
  58. package/{js/parallax.js → src/parallax.ts} +47 -60
  59. package/{js/pushpin.js → src/pushpin.ts} +19 -47
  60. package/{js/range.js → src/range.ts} +58 -139
  61. package/{js/scrollspy.js → src/scrollspy.ts} +81 -153
  62. package/src/select.ts +448 -0
  63. package/{js/sidenav.js → src/sidenav.ts} +96 -202
  64. package/src/slider.ts +415 -0
  65. package/src/tabs.ts +293 -0
  66. package/src/tapTarget.ts +240 -0
  67. package/{js/timepicker.js → src/timepicker.ts} +268 -272
  68. package/{js/toasts.js → src/toasts.ts} +75 -134
  69. package/{js/tooltip.js → src/tooltip.ts} +59 -96
  70. package/src/waves.ts +70 -0
  71. package/extras/noUiSlider/nouislider.css +0 -404
  72. package/extras/noUiSlider/nouislider.js +0 -2147
  73. package/extras/noUiSlider/nouislider.min.js +0 -1
  74. package/js/anime.min.js +0 -34
  75. package/js/autocomplete.js +0 -479
  76. package/js/cards.js +0 -40
  77. package/js/cash.js +0 -960
  78. package/js/characterCounter.js +0 -136
  79. package/js/chips.js +0 -486
  80. package/js/collapsible.js +0 -275
  81. package/js/forms.js +0 -285
  82. package/js/global.js +0 -428
  83. package/js/materialbox.js +0 -453
  84. package/js/modal.js +0 -382
  85. package/js/select.js +0 -391
  86. package/js/slider.js +0 -497
  87. package/js/tabs.js +0 -402
  88. package/js/tapTarget.js +0 -315
  89. package/js/waves.js +0 -615
  90. package/sass/components/_waves.scss +0 -187
@@ -1,7 +1,11 @@
1
1
  /* Select Field
2
2
  ========================================================================== */
3
3
 
4
- select.browser-default { opacity: 1; }
4
+ select.browser-default {
5
+ opacity: 1;
6
+ color: $select-input-color;
7
+ }
8
+
5
9
  select {
6
10
  opacity: 0;
7
11
  background-color: $select-background;
@@ -12,11 +16,13 @@ select {
12
16
  height: $input-height;
13
17
  }
14
18
 
15
- .select-label {
16
- position: absolute;
17
- }
19
+ // .select-label {
20
+ // position: absolute;
21
+ // }
22
+
18
23
 
19
24
  .select-wrapper {
25
+ /*
20
26
  &.valid .helper-text[data-success],
21
27
  &.invalid ~ .helper-text[data-error] {
22
28
  @extend %hidden-text;
@@ -26,9 +32,8 @@ select {
26
32
  & > input.select-dropdown {
27
33
  @extend %valid-input-style;
28
34
  }
29
-
30
35
  & ~ .helper-text:after {
31
- @extend %custom-success-message;
36
+ //@extend %custom-success-message;
32
37
  }
33
38
  }
34
39
 
@@ -37,9 +42,8 @@ select {
37
42
  & > input.select-dropdown:focus {
38
43
  @extend %invalid-input-style;
39
44
  }
40
-
41
45
  & ~ .helper-text:after {
42
- @extend %custom-error-message;
46
+ //@extend %custom-error-message;
43
47
  }
44
48
  }
45
49
 
@@ -48,14 +52,17 @@ select {
48
52
  width: 100%;
49
53
  pointer-events: none;
50
54
  }
51
-
52
55
  & + label:after {
53
- @extend %input-after-style;
56
+ //@extend %input-after-style;
54
57
  }
58
+ */
59
+
60
+
55
61
 
56
62
  position: relative;
57
63
 
58
- input.select-dropdown {
64
+ /*
65
+ input.select-dropdown {
59
66
  &:focus {
60
67
  border-bottom: 1px solid $input-focus-color;
61
68
  }
@@ -74,7 +81,9 @@ select {
74
81
  display: block;
75
82
  user-select:none;
76
83
  z-index: 1;
84
+ color: $select-input-color;
77
85
  }
86
+ */
78
87
 
79
88
  .caret {
80
89
  position: absolute;
@@ -83,14 +92,16 @@ select {
83
92
  bottom: 0;
84
93
  margin: auto 0;
85
94
  z-index: 0;
86
- fill: rgba(0,0,0,.87);
95
+ fill: $select-input-color;
87
96
  }
88
97
 
98
+ /*
89
99
  & + label {
90
100
  position: absolute;
91
101
  top: -26px;
92
102
  font-size: $label-font-size;
93
103
  }
104
+ */
94
105
 
95
106
  // Hide select with overflow hidden instead of using display none
96
107
  // (this prevents form validation errors with hidden form elements)
@@ -143,33 +154,32 @@ body.keyboard-focused {
143
154
 
144
155
  .select-dropdown.dropdown-content {
145
156
  li {
146
- &:hover {
157
+ &:hover:not(.disabled) {
147
158
  background-color: $select-option-hover;
148
159
  }
149
160
 
150
- &.selected {
161
+ &.selected:not(.disabled) {
151
162
  background-color: $select-option-selected;
152
163
  }
153
164
  }
154
165
  }
155
166
 
167
+ /*
156
168
  // Prefix Icons
157
169
  .prefix ~ .select-wrapper {
158
170
  margin-left: 3rem;
159
171
  width: 92%;
160
172
  width: calc(100% - 3rem);
161
173
  }
162
-
163
174
  .prefix ~ label { margin-left: 3rem; }
164
-
165
175
  // Suffix Icons
166
176
  .suffix ~ .select-wrapper {
167
177
  margin-right: 3rem;
168
178
  width: 92%;
169
179
  width: calc(100% - 3rem);
170
180
  }
171
-
172
181
  .suffix ~ label { margin-right: 3rem; }
182
+ */
173
183
 
174
184
  // Icons
175
185
  .select-dropdown li {
@@ -186,11 +196,11 @@ body.keyboard-focused {
186
196
  border-top: 1px solid $dropdown-hover-bg-color;
187
197
 
188
198
  &.selected > span {
189
- color: rgba(0, 0, 0, .7);
199
+ color: $font-color-main;
190
200
  }
191
201
 
192
202
  & > span {
193
- color: rgba(0, 0, 0, .4);
203
+ color: $font-color-medium;
194
204
  }
195
205
 
196
206
  & ~ li.optgroup-option {
@@ -16,8 +16,8 @@
16
16
  width: 0;
17
17
  height: 0;
18
18
 
19
- &:checked:not([disabled]) {
20
- background-color: $switch-checked-lever-bg;
19
+ &:checked + .lever{
20
+ background-color: $switch-track-checked-bg;
21
21
  }
22
22
 
23
23
  &:checked + .lever {
@@ -26,7 +26,7 @@
26
26
  }
27
27
 
28
28
  &:after {
29
- background-color: $switch-bg-color;
29
+ background-color: $switch-thumb-checked-color;
30
30
  }
31
31
  }
32
32
  }
@@ -37,7 +37,7 @@
37
37
  position: relative;
38
38
  width: 36px;
39
39
  height: 14px;
40
- background-color: $switch-unchecked-lever-bg;
40
+ background-color: $switch-track-unchecked-bg;
41
41
  border-radius: $switch-radius;
42
42
  margin-right: 10px;
43
43
  transition: background 0.3s ease;
@@ -56,36 +56,40 @@
56
56
  transition: left 0.3s ease, background .3s ease, box-shadow 0.1s ease, transform .1s ease;
57
57
  }
58
58
 
59
- &:before {
60
- background-color: transparentize($switch-bg-color, .85);
61
- }
62
-
63
59
  &:after {
64
- background-color: $switch-unchecked-bg;
60
+ background-color: $switch-thumb-unchecked-color;
65
61
  box-shadow: 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12);
66
62
  }
67
63
  }
68
64
 
65
+ input[type=checkbox]:not(:disabled) ~ .lever:active:before,
66
+ input[type=checkbox]:not(:disabled).tabbed:focus ~ .lever::before,
67
+ input[type=checkbox]:not(:disabled) ~ .lever:hover::before {
68
+ transform: scale(2.4);
69
+ }
70
+
71
+ input[type=checkbox]:checked:not(:disabled) ~ .lever:hover::before {
72
+ background-color: $switch-reaction-checked-hover-color;
73
+ }
74
+
69
75
  // Switch active style
70
76
  input[type=checkbox]:checked:not(:disabled) ~ .lever:active::before,
71
77
  input[type=checkbox]:checked:not(:disabled).tabbed:focus ~ .lever::before {
72
- transform: scale(2.4);
73
- background-color: transparentize($switch-bg-color, .85);
78
+ background-color: $switch-reaction-checked-focus-color;
79
+ }
80
+
81
+ input[type=checkbox]:not(:disabled) ~ .lever:hover::before {
82
+ background-color: $switch-reaction-unchecked-hover-color;
74
83
  }
75
84
 
76
85
  input[type=checkbox]:not(:disabled) ~ .lever:active:before,
77
86
  input[type=checkbox]:not(:disabled).tabbed:focus ~ .lever::before {
78
- transform: scale(2.4);
79
- background-color: rgba(0,0,0,.08);
87
+ background-color: $switch-reaction-unchecked-focus-color;
80
88
  }
81
89
 
82
90
  // Disabled Styles
83
91
  .switch input[type=checkbox][disabled] + .lever {
84
92
  cursor: default;
85
- background-color: rgba(0,0,0,.12);
93
+ opacity: 0.5;
86
94
  }
87
95
 
88
- .switch label input[type=checkbox][disabled] + .lever:after,
89
- .switch label input[type=checkbox][disabled]:checked + .lever:after {
90
- background-color: $input-disabled-solid-color;
91
- }
@@ -25,7 +25,6 @@
25
25
  @import "components/tooltip";
26
26
  @import "components/buttons";
27
27
  @import "components/dropdown";
28
- @import "components/waves";
29
28
  @import "components/modal";
30
29
  @import "components/collapsible";
31
30
  @import "components/chips";
@@ -40,3 +39,4 @@
40
39
  @import "components/pulse";
41
40
  @import "components/datepicker";
42
41
  @import "components/timepicker";
42
+ @import "components/_theme_variables";
@@ -0,0 +1,459 @@
1
+ import { Component } from "./component";
2
+ import { M } from "./global";
3
+ import { Dropdown } from "./dropdown";
4
+
5
+ let _defaults = {
6
+ data: [], // Autocomplete data set
7
+ onAutocomplete: null, // Callback for when autocompleted
8
+ dropdownOptions: {
9
+ // Default dropdown options
10
+ autoFocus: false,
11
+ closeOnClick: false,
12
+ coverTrigger: false
13
+ },
14
+ minLength: 1, // Min characters before autocomplete starts
15
+ isMultiSelect: false,
16
+ onSearch: function(text, autocomplete) {
17
+ const filteredData = autocomplete.options.data.filter(item => {
18
+ return Object.keys(item)
19
+ .map(key => item[key].toString().toLowerCase().indexOf(text.toLowerCase()) >= 0)
20
+ .some(isMatch => isMatch);
21
+ });
22
+ autocomplete.setMenuItems(filteredData);
23
+ },
24
+ maxDropDownHeight: '300px',
25
+ allowUnsafeHTML: false
26
+ };
27
+
28
+
29
+ export class Autocomplete extends Component {
30
+ el: HTMLInputElement;
31
+ isOpen: boolean;
32
+ count: number;
33
+ activeIndex: number;
34
+ private oldVal: any;
35
+ private $inputField: any;
36
+ private $active: HTMLElement|null;
37
+ private _mousedown: boolean;
38
+ private _handleInputBlurBound: any;
39
+ private _handleInputKeyupAndFocusBound: any;
40
+ private _handleInputKeydownBound: any;
41
+ private _handleInputClickBound: any;
42
+ private _handleContainerMousedownAndTouchstartBound: any;
43
+ private _handleContainerMouseupAndTouchendBound: any;
44
+ container: HTMLElement;
45
+ dropdown: Dropdown;
46
+ static _keydown: boolean;
47
+ selectedValues: any[];
48
+ menuItems: any[];
49
+
50
+
51
+ constructor(el, options) {
52
+ super(Autocomplete, el, options);
53
+ (this.el as any).M_Autocomplete = this;
54
+ this.options = {...Autocomplete.defaults, ...options};
55
+ this.isOpen = false;
56
+ this.count = 0;
57
+ this.activeIndex = -1;
58
+ this.oldVal;
59
+ this.selectedValues = [];
60
+ this.menuItems = [];
61
+ this.$active = null;
62
+ this._mousedown = false;
63
+ this._setupDropdown();
64
+ this._setupEventHandlers();
65
+ }
66
+ static get defaults() {
67
+ return _defaults;
68
+ }
69
+ static init(els, options) {
70
+ return super.init(this, els, options);
71
+ }
72
+ static getInstance(el) {
73
+ let domElem = el.jquery ? el[0] : el;
74
+ return domElem.M_Autocomplete;
75
+ }
76
+
77
+ destroy() {
78
+ this._removeEventHandlers();
79
+ this._removeDropdown();
80
+ (this.el as any).M_Autocomplete = undefined;
81
+ }
82
+
83
+ _setupEventHandlers() {
84
+ this._handleInputBlurBound = this._handleInputBlur.bind(this);
85
+ this._handleInputKeyupAndFocusBound = this._handleInputKeyupAndFocus.bind(this);
86
+ this._handleInputKeydownBound = this._handleInputKeydown.bind(this);
87
+ this._handleInputClickBound = this._handleInputClick.bind(this);
88
+ this._handleContainerMousedownAndTouchstartBound = this._handleContainerMousedownAndTouchstart.bind(
89
+ this
90
+ );
91
+ this._handleContainerMouseupAndTouchendBound = this._handleContainerMouseupAndTouchend.bind(
92
+ this
93
+ );
94
+ this.el.addEventListener('blur', this._handleInputBlurBound);
95
+ this.el.addEventListener('keyup', this._handleInputKeyupAndFocusBound);
96
+ this.el.addEventListener('focus', this._handleInputKeyupAndFocusBound);
97
+ this.el.addEventListener('keydown', this._handleInputKeydownBound);
98
+ this.el.addEventListener('click', this._handleInputClickBound);
99
+ this.container.addEventListener(
100
+ 'mousedown',
101
+ this._handleContainerMousedownAndTouchstartBound
102
+ );
103
+ this.container.addEventListener('mouseup', this._handleContainerMouseupAndTouchendBound);
104
+ if (typeof window.ontouchstart !== 'undefined') {
105
+ this.container.addEventListener(
106
+ 'touchstart',
107
+ this._handleContainerMousedownAndTouchstartBound
108
+ );
109
+ this.container.addEventListener('touchend', this._handleContainerMouseupAndTouchendBound);
110
+ }
111
+ }
112
+
113
+ _removeEventHandlers() {
114
+ this.el.removeEventListener('blur', this._handleInputBlurBound);
115
+ this.el.removeEventListener('keyup', this._handleInputKeyupAndFocusBound);
116
+ this.el.removeEventListener('focus', this._handleInputKeyupAndFocusBound);
117
+ this.el.removeEventListener('keydown', this._handleInputKeydownBound);
118
+ this.el.removeEventListener('click', this._handleInputClickBound);
119
+ this.container.removeEventListener(
120
+ 'mousedown',
121
+ this._handleContainerMousedownAndTouchstartBound
122
+ );
123
+ this.container.removeEventListener('mouseup', this._handleContainerMouseupAndTouchendBound);
124
+
125
+ if (typeof window.ontouchstart !== 'undefined') {
126
+ this.container.removeEventListener(
127
+ 'touchstart',
128
+ this._handleContainerMousedownAndTouchstartBound
129
+ );
130
+ this.container.removeEventListener(
131
+ 'touchend',
132
+ this._handleContainerMouseupAndTouchendBound
133
+ );
134
+ }
135
+ }
136
+
137
+ _setupDropdown() {
138
+ this.container = document.createElement('ul');
139
+ this.container.style.maxHeight = this.options.maxDropDownHeight;
140
+ this.container.id = `autocomplete-options-${M.guid()}`;
141
+ this.container.classList.add('autocomplete-content', 'dropdown-content');
142
+ this.el.setAttribute('data-target', this.container.id);
143
+
144
+ // ! Issue in Component Dropdown: _placeDropdown moves dom-position
145
+ this.el.parentElement.appendChild(this.container);
146
+
147
+ // Initialize dropdown
148
+ let dropdownOptions = {
149
+ ...Autocomplete.defaults.dropdownOptions,
150
+ ...this.options.dropdownOptions
151
+ };
152
+ let userOnItemClick = dropdownOptions.onItemClick;
153
+ // Ensuring the select Option call when user passes custom onItemClick function to dropdown
154
+ dropdownOptions.onItemClick = (li) => {
155
+ if (!li) return;
156
+ const entryID = li.getAttribute('data-id');
157
+ this.selectOption(entryID);
158
+ // Handle user declared onItemClick if needed
159
+ if (userOnItemClick && typeof userOnItemClick === 'function')
160
+ userOnItemClick.call(this.dropdown, this.el);
161
+ };
162
+ this.dropdown = M.Dropdown.init(this.el, dropdownOptions);
163
+
164
+ // ! Workaround for Label: move label up again
165
+ // TODO: Just use PopperJS in future!
166
+ const label = this.el.parentElement.querySelector('label');
167
+ if (label) this.el.after(label);
168
+
169
+ // Sketchy removal of dropdown click handler
170
+ this.el.removeEventListener('click', this.dropdown._handleClickBound);
171
+ // Set Value if already set in HTML
172
+ if (this.el.value) this.selectOption(this.el.value);
173
+ // Add StatusInfo
174
+ const div = document.createElement('div');
175
+ div.classList.add('status-info');
176
+ div.setAttribute('style', 'position: absolute;right:0;top:0;');
177
+ this.el.parentElement.appendChild(div);
178
+ this._updateSelectedInfo();
179
+ }
180
+
181
+ _removeDropdown() {
182
+ this.container.parentNode.removeChild(this.container);
183
+ }
184
+
185
+ _handleInputBlur() {
186
+ if (!this._mousedown) {
187
+ this.close();
188
+ this._resetAutocomplete();
189
+ }
190
+ }
191
+
192
+ _handleInputKeyupAndFocus(e) {
193
+ if (e.type === 'keyup') Autocomplete._keydown = false;
194
+ this.count = 0;
195
+ const actualValue = this.el.value.toLowerCase();
196
+ // Don't capture enter or arrow key usage.
197
+ if (e.keyCode === 13 || e.keyCode === 38 || e.keyCode === 40) return;
198
+ // Check if the input isn't empty
199
+ // Check if focus triggered by tab
200
+ if (this.oldVal !== actualValue && (M.tabPressed || e.type !== 'focus')) {
201
+ this.open();
202
+ }
203
+ // Value has changed!
204
+ if (this.oldVal !== actualValue) {
205
+ this._setStatusLoading();
206
+ this.options.onSearch(this.el.value, this);
207
+ }
208
+ // Reset Single-Select when Input cleared
209
+ if (!this.options.isMultiSelect && this.el.value.length === 0) {
210
+ this.selectedValues = [];
211
+ this._triggerChanged();
212
+ }
213
+ this.oldVal = actualValue;
214
+ }
215
+
216
+ _handleInputKeydown(e) {
217
+ Autocomplete._keydown = true;
218
+ // Arrow keys and enter key usage
219
+ const keyCode = e.keyCode;
220
+ const numItems = this.container.querySelectorAll('li').length;
221
+ // select element on Enter
222
+ if (keyCode === M.keys.ENTER && this.activeIndex >= 0) {
223
+ const liElement = this.container.querySelectorAll('li')[this.activeIndex];
224
+ if (liElement) {
225
+ this.selectOption(liElement.getAttribute('data-id'));
226
+ e.preventDefault();
227
+ }
228
+ return;
229
+ }
230
+ // Capture up and down key
231
+ if (keyCode === M.keys.ARROW_UP || keyCode === M.keys.ARROW_DOWN) {
232
+ e.preventDefault();
233
+ if (keyCode === M.keys.ARROW_UP && this.activeIndex > 0) this.activeIndex--;
234
+ if (keyCode === M.keys.ARROW_DOWN && this.activeIndex < numItems - 1) this.activeIndex++;
235
+ this.$active?.classList.remove('active');
236
+ if (this.activeIndex >= 0) {
237
+ this.$active = this.container.querySelectorAll('li')[this.activeIndex];
238
+ this.$active?.classList.add('active');
239
+ // Focus selected
240
+ this.container.children[this.activeIndex].scrollIntoView({
241
+ behavior: 'smooth',
242
+ block: 'nearest',
243
+ inline: 'nearest'
244
+ });
245
+ }
246
+ }
247
+ }
248
+
249
+ _handleInputClick(e) {
250
+ this.open();
251
+ }
252
+
253
+ _handleContainerMousedownAndTouchstart(e) {
254
+ this._mousedown = true;
255
+ }
256
+
257
+ _handleContainerMouseupAndTouchend(e) {
258
+ this._mousedown = false;
259
+ }
260
+
261
+ _resetCurrentElementPosition() {
262
+ this.activeIndex = -1;
263
+ this.$active?.classList.remove('active');
264
+ }
265
+
266
+ _resetAutocomplete() {
267
+ this.container.replaceChildren();
268
+ this._resetCurrentElementPosition();
269
+ this.oldVal = null;
270
+ this.isOpen = false;
271
+ this._mousedown = false;
272
+ }
273
+
274
+ _highlightPartialText(input, label) {
275
+ const start = label.toLowerCase().indexOf('' + input.toLowerCase() + '');
276
+ const end = start + input.length - 1;
277
+ //custom filters may return results where the string does not match any part
278
+ if (start == -1 || end == -1) {
279
+ return [label, '', ''];
280
+ }
281
+ return [label.slice(0, start), label.slice(start, end + 1), label.slice(end + 1)];
282
+ }
283
+
284
+ _createDropdownItem(entry) {
285
+ const item = document.createElement('li');
286
+ item.setAttribute('data-id', entry.id);
287
+ item.setAttribute(
288
+ 'style',
289
+ 'display:grid; grid-auto-flow: column; user-select: none; align-items: center;'
290
+ );
291
+ // Checkbox
292
+ if (this.options.isMultiSelect) {
293
+ item.innerHTML = `
294
+ <div class="item-selection" style="text-align:center;">
295
+ <input type="checkbox"${
296
+ this.selectedValues.some((sel) => sel.id === entry.id) ? ' checked="checked"' : ''
297
+ }><span style="padding-left:21px;"></span>
298
+ </div>`;
299
+ }
300
+ // Image
301
+ if (entry.image) {
302
+ const img = document.createElement('img');
303
+ img.classList.add('circle');
304
+ img.src = entry.image;
305
+ item.appendChild(img);
306
+ }
307
+
308
+ // Text
309
+ const inputText = this.el.value.toLowerCase();
310
+ const parts = this._highlightPartialText(inputText, (entry.text || entry.id).toString());
311
+ const div = document.createElement('div');
312
+ div.setAttribute('style', 'line-height:1.2;font-weight:500;');
313
+ if (this.options.allowUnsafeHTML) {
314
+ div.innerHTML = parts[0] + '<span class="highlight">' + parts[1] + '</span>' + parts[2];
315
+ } else {
316
+ div.appendChild(document.createTextNode(parts[0]));
317
+ if (parts[1]) {
318
+ const highlight = document.createElement('span');
319
+ highlight.textContent = parts[1];
320
+ highlight.classList.add('highlight');
321
+ div.appendChild(highlight);
322
+ div.appendChild(document.createTextNode(parts[2]));
323
+ }
324
+ }
325
+
326
+ const itemText = document.createElement('div');
327
+ itemText.classList.add('item-text');
328
+ itemText.setAttribute('style', 'padding:5px;overflow:hidden;');
329
+ item.appendChild(itemText);
330
+ item.querySelector('.item-text').appendChild(div);
331
+ // Description
332
+ if (typeof entry.description === 'string' || (typeof entry.description === 'number' && !isNaN(entry.description))) {
333
+ const description = document.createElement('small');
334
+ description.setAttribute(
335
+ 'style',
336
+ 'line-height:1.3;color:grey;white-space:nowrap;text-overflow:ellipsis;display:block;width:90%;overflow:hidden;'
337
+ );
338
+ description.innerText = entry.description;
339
+ item.querySelector('.item-text').appendChild(description);
340
+ }
341
+ // Set Grid
342
+ const getGridConfig = () => {
343
+ if (this.options.isMultiSelect) {
344
+ if (entry.image) return '40px min-content auto'; // cb-img-txt
345
+ return '40px auto'; // cb-txt
346
+ }
347
+ if (entry.image) return 'min-content auto'; // img-txt
348
+ return 'auto'; // txt
349
+ };
350
+ item.style.gridTemplateColumns = getGridConfig();
351
+ return item;
352
+ }
353
+
354
+ _renderDropdown() {
355
+ this._resetAutocomplete();
356
+ // Check if Data is empty
357
+ if (this.menuItems.length === 0) {
358
+ this.menuItems = this.selectedValues; // Show selected Items
359
+ }
360
+ for (let i = 0; i < this.menuItems.length; i++) {
361
+ const item = this._createDropdownItem(this.menuItems[i]);
362
+ this.container.append(item);
363
+ }
364
+ }
365
+
366
+ _setStatusLoading() {
367
+ this.el.parentElement.querySelector(
368
+ '.status-info'
369
+ ).innerHTML = `<div style="height:100%;width:50px;"><svg version="1.1" id="L4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 100 100" enable-background="new 0 0 0 0" xml:space="preserve">
370
+ <circle fill="#888c" stroke="none" cx="6" cy="50" r="6"><animate attributeName="opacity" dur="1s" values="0;1;0" repeatCount="indefinite" begin="0.1"/></circle>
371
+ <circle fill="#888c" stroke="none" cx="26" cy="50" r="6"><animate attributeName="opacity" dur="1s" values="0;1;0" repeatCount="indefinite" begin="0.2"/></circle>
372
+ <circle fill="#888c" stroke="none" cx="46" cy="50" r="6"><animate attributeName="opacity" dur="1s" values="0;1;0" repeatCount="indefinite" begin="0.3"/></circle>
373
+ </svg></div>`;
374
+ }
375
+
376
+ _updateSelectedInfo() {
377
+ const statusElement = this.el.parentElement.querySelector('.status-info');
378
+ if (statusElement) {
379
+ if (this.options.isMultiSelect) statusElement.innerHTML = this.selectedValues.length.toString();
380
+ else statusElement.innerHTML = '';
381
+ }
382
+ }
383
+
384
+ _refreshInputText() {
385
+ if (this.selectedValues.length === 1) {
386
+ const entry = this.selectedValues[0];
387
+ this.el.value = entry.text || entry.id; // Write Text to Input
388
+ }
389
+ }
390
+
391
+ _triggerChanged() {
392
+ this.el.dispatchEvent(new Event('change'));
393
+ // Trigger Autocomplete Event
394
+ if (typeof this.options.onAutocomplete === 'function')
395
+ this.options.onAutocomplete.call(this, this.selectedValues);
396
+ }
397
+
398
+ open() {
399
+ const inputText = this.el.value.toLowerCase();
400
+ this._resetAutocomplete();
401
+ if (inputText.length >= this.options.minLength) {
402
+ this.isOpen = true;
403
+ this._renderDropdown();
404
+ }
405
+ // Open dropdown
406
+ if (!this.dropdown.isOpen) {
407
+ setTimeout(() => {
408
+ this.dropdown.open();
409
+ }, 100);
410
+ }
411
+ else this.dropdown.recalculateDimensions(); // Recalculate dropdown when its already open
412
+ }
413
+
414
+ close() {
415
+ this.dropdown.close();
416
+ }
417
+
418
+ setMenuItems(menuItems) {
419
+ this.menuItems = menuItems;
420
+ this.open();
421
+ this._updateSelectedInfo();
422
+ }
423
+
424
+ setValues(entries) {
425
+ this.selectedValues = entries;
426
+ this._updateSelectedInfo();
427
+ if (!this.options.isMultiSelect) {
428
+ this._refreshInputText();
429
+ }
430
+ this._triggerChanged();
431
+ }
432
+
433
+ selectOption(id) {
434
+ const entry = this.menuItems.find((item) => item.id == id);
435
+ if (!entry) return;
436
+ // Toggle Checkbox
437
+ const li = this.container.querySelector('li[data-id="'+id+'"]');
438
+ if (!li) return;
439
+ if (this.options.isMultiSelect) {
440
+ const checkbox = <HTMLInputElement|null>li.querySelector('input[type="checkbox"]');
441
+ checkbox.checked = !checkbox.checked;
442
+ if (checkbox.checked) this.selectedValues.push(entry);
443
+ else
444
+ this.selectedValues = this.selectedValues.filter(
445
+ (selectedEntry) => selectedEntry.id !== entry.id
446
+ );
447
+ this.el.focus();
448
+ } else {
449
+ // Single-Select
450
+ this.selectedValues = [entry];
451
+ this._refreshInputText();
452
+ this._resetAutocomplete();
453
+ this.close();
454
+ }
455
+ this._updateSelectedInfo();
456
+ this._triggerChanged();
457
+ }
458
+ }
459
+