@internetstiftelsen/styleguide 4.0.12-beta.0.5 → 4.0.12
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/dist/components.js
CHANGED
|
@@ -1,140 +1,224 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
var className = 'm-multi-select';
|
|
5
|
-
var multiSelectElements = document.querySelectorAll('.js-' + className);
|
|
6
|
-
var namespace = void 0;
|
|
3
|
+
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
|
7
4
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
5
|
+
var _className = require('../../assets/js/className');
|
|
6
|
+
|
|
7
|
+
var _className2 = _interopRequireDefault(_className);
|
|
8
|
+
|
|
9
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
10
|
+
|
|
11
|
+
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
12
|
+
|
|
13
|
+
var MultiSelect = function () {
|
|
14
|
+
function MultiSelect(el) {
|
|
15
|
+
var _this = this;
|
|
16
|
+
|
|
17
|
+
_classCallCheck(this, MultiSelect);
|
|
18
|
+
|
|
19
|
+
this.onInput = function () {
|
|
20
|
+
var value = _this.input.value;
|
|
21
|
+
|
|
22
|
+
// Clear suggestions if less than 2 characters are typed
|
|
23
|
+
|
|
24
|
+
if (value.length < 2) {
|
|
25
|
+
_this.clearSuggestions();
|
|
26
|
+
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
var suggestions = _this.filterData(value);
|
|
31
|
+
|
|
32
|
+
_this.populateSuggestions(suggestions);
|
|
33
|
+
_this.resetFocus();
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
this.onKeyDown = function (e) {
|
|
37
|
+
if (e.keyCode === 40) {
|
|
38
|
+
_this.highlight('down');
|
|
39
|
+
} else if (e.keyCode === 38) {
|
|
40
|
+
_this.highlight('up');
|
|
41
|
+
} else if (e.keyCode === 13) {
|
|
42
|
+
e.preventDefault();
|
|
43
|
+
|
|
44
|
+
_this.selectHighlighted();
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
this.onClick = function (e) {
|
|
49
|
+
if (e.target.classList.contains((0, _className2.default)(_this.baseClassName + '__suggestion-btn'))) {
|
|
50
|
+
_this.addItem(e.target.textContent);
|
|
51
|
+
_this.clearSuggestions();
|
|
52
|
+
_this.input.value = '';
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
this.element = el;
|
|
57
|
+
this.baseClassName = 'm-multi-select';
|
|
58
|
+
this.currentFocus = -1;
|
|
59
|
+
this.input = this.element.querySelector('.js-' + this.baseClassName + '__input');
|
|
60
|
+
this.suggestionsBox = this.element.querySelector('.js-' + this.baseClassName + '-suggestions-box');
|
|
61
|
+
this.selectedItemsList = this.element.querySelector('.js-m-multi-select-selected-items');
|
|
62
|
+
this.selectedItems = [];
|
|
63
|
+
this.data = [];
|
|
64
|
+
|
|
65
|
+
this.getData();
|
|
66
|
+
this.attach();
|
|
29
67
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
function
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
var buttonTextContainer = document.createElement('span');
|
|
44
|
-
buttonTextContainer.classList.add('u-visuallyhidden');
|
|
45
|
-
removeBtn.appendChild(buttonTextContainer);
|
|
46
|
-
buttonTextContainer.textContent = 'Ta bort ' + item; // Accessibility label for screen readers
|
|
47
|
-
|
|
48
|
-
// Event listener for removing the selected item
|
|
49
|
-
removeBtn.addEventListener('click', function () {
|
|
50
|
-
removeItem(newItem, Array.from(selectedItemsList.children).indexOf(newItem));
|
|
51
|
-
});
|
|
52
|
-
newItem.appendChild(removeBtn);
|
|
53
|
-
selectedItemsList.appendChild(newItem);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Remove an item and manage focus appropriately
|
|
57
|
-
function removeItem(item, index) {
|
|
58
|
-
var selectedItemsList = document.querySelector('.js-m-multi-select-selected-items');
|
|
59
|
-
selectedItemsList.removeChild(item);
|
|
60
|
-
|
|
61
|
-
var remainingItems = selectedItemsList.getElementsByTagName('div');
|
|
62
|
-
// Focus management: set focus to the next item, or the search input if no items left
|
|
63
|
-
if (remainingItems.length > 0) {
|
|
64
|
-
if (index < remainingItems.length) {
|
|
65
|
-
remainingItems[index].getElementsByTagName('button')[0].focus();
|
|
66
|
-
} else {
|
|
67
|
-
remainingItems[remainingItems.length - 1].getElementsByTagName('button')[0].focus();
|
|
68
|
+
|
|
69
|
+
_createClass(MultiSelect, [{
|
|
70
|
+
key: 'getData',
|
|
71
|
+
value: function getData() {
|
|
72
|
+
var id = this.input.getAttribute('data-multi-select-suggestions');
|
|
73
|
+
var el = document.getElementById(id);
|
|
74
|
+
|
|
75
|
+
if (!el) {
|
|
76
|
+
this.data = [];
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
this.data = JSON.parse(el.textContent);
|
|
68
81
|
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
var multiSelectInput = multiSelectElement.querySelector('.js-' + className + '__input');
|
|
76
|
-
var suggestionsBox = multiSelectElement.querySelector('.js-' + className + '-suggestions-box');
|
|
77
|
-
var suggestionsData = multiSelectInput.getAttribute('data-multi-select-suggestions');
|
|
78
|
-
|
|
79
|
-
// Event listener for input changes in the search field
|
|
80
|
-
multiSelectInput.addEventListener('input', function () {
|
|
81
|
-
var value = this.value;
|
|
82
|
-
// Clear suggestions if less than 2 characters are typed
|
|
83
|
-
if (value.length < 2) {
|
|
84
|
-
suggestionsBox.innerHTML = '';
|
|
85
|
-
return;
|
|
82
|
+
}, {
|
|
83
|
+
key: 'attach',
|
|
84
|
+
value: function attach() {
|
|
85
|
+
this.input.addEventListener('input', this.onInput);
|
|
86
|
+
this.input.addEventListener('keydown', this.onKeyDown);
|
|
87
|
+
this.suggestionsBox.addEventListener('click', this.onClick);
|
|
86
88
|
}
|
|
89
|
+
}, {
|
|
90
|
+
key: 'setFocus',
|
|
91
|
+
value: function setFocus(index) {
|
|
92
|
+
this.currentFocus = index;
|
|
93
|
+
}
|
|
94
|
+
}, {
|
|
95
|
+
key: 'resetFocus',
|
|
96
|
+
value: function resetFocus() {
|
|
97
|
+
this.setFocus(-1);
|
|
98
|
+
}
|
|
99
|
+
}, {
|
|
100
|
+
key: 'clearSuggestions',
|
|
101
|
+
value: function clearSuggestions() {
|
|
102
|
+
this.suggestionsBox.innerHTML = '';
|
|
103
|
+
}
|
|
104
|
+
}, {
|
|
105
|
+
key: 'filterData',
|
|
106
|
+
value: function filterData(query) {
|
|
107
|
+
var _this2 = this;
|
|
108
|
+
|
|
109
|
+
return this.data.filter(function (item) {
|
|
110
|
+
return item.name.toLowerCase().startsWith(query.toLowerCase());
|
|
111
|
+
}).filter(function (item) {
|
|
112
|
+
return !_this2.selectedItems.includes(item.name);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}, {
|
|
116
|
+
key: 'populateSuggestions',
|
|
117
|
+
value: function populateSuggestions(suggestions) {
|
|
118
|
+
var cls = (0, _className2.default)(this.baseClassName + '__suggestion-btn');
|
|
119
|
+
this.suggestionsBox.innerHTML = suggestions.map(function (item) {
|
|
120
|
+
return '<button class=\'' + cls + '\' tabindex=\'0\'>' + item.name + '</button>';
|
|
121
|
+
}).join('');
|
|
122
|
+
}
|
|
123
|
+
}, {
|
|
124
|
+
key: 'removeItem',
|
|
125
|
+
value: function removeItem(item, index) {
|
|
126
|
+
var selectedItemsList = this.element.querySelector('.js-m-multi-select-selected-items');
|
|
127
|
+
selectedItemsList.removeChild(item);
|
|
128
|
+
|
|
129
|
+
var remainingItems = selectedItemsList.getElementsByTagName('div');
|
|
130
|
+
|
|
131
|
+
// Focus management: set focus to the next item, or the search input if no items left
|
|
132
|
+
if (remainingItems.length > 0) {
|
|
133
|
+
if (index < remainingItems.length) {
|
|
134
|
+
remainingItems[index].getElementsByTagName('button')[0].focus();
|
|
135
|
+
} else {
|
|
136
|
+
remainingItems[remainingItems.length - 1].getElementsByTagName('button')[0].focus();
|
|
137
|
+
}
|
|
138
|
+
} else {
|
|
139
|
+
this.input.focus();
|
|
140
|
+
}
|
|
87
141
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
// Populate the suggestions box with the filtered results
|
|
97
|
-
suggestionsBox.innerHTML = filtered.map(function (item) {
|
|
98
|
-
return '<button class=\'' + namespace + 'm-multi-select__suggestion-btn\' tabindex=\'0\'>' + item.name + '</button>';
|
|
99
|
-
}).join('');
|
|
100
|
-
// Reset the current focus
|
|
101
|
-
currentFocus = -1;
|
|
102
|
-
});
|
|
142
|
+
this.selectedItems = this.selectedItems.filter(function (name) {
|
|
143
|
+
return name !== item.firstChild.textContent.trim();
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}, {
|
|
147
|
+
key: 'addItem',
|
|
148
|
+
value: function addItem(item) {
|
|
149
|
+
var _this3 = this;
|
|
103
150
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
151
|
+
var newItem = document.createElement('li');
|
|
152
|
+
newItem.textContent = item + ' ';
|
|
153
|
+
newItem.classList.add((0, _className2.default)('a-tag'));
|
|
154
|
+
newItem.classList.add((0, _className2.default)(this.baseClassName + '__tag'));
|
|
155
|
+
|
|
156
|
+
var removeBtn = document.createElement('button');
|
|
157
|
+
removeBtn.classList.add((0, _className2.default)(this.baseClassName + '-selected-items__remove-btn'));
|
|
158
|
+
|
|
159
|
+
var buttonTextContainer = document.createElement('span');
|
|
160
|
+
buttonTextContainer.classList.add('u-visuallyhidden');
|
|
161
|
+
removeBtn.appendChild(buttonTextContainer);
|
|
162
|
+
buttonTextContainer.textContent = 'Ta bort ' + item; // Accessibility label for screen readers
|
|
163
|
+
|
|
164
|
+
// Event listener for removing the selected item
|
|
165
|
+
removeBtn.addEventListener('click', function () {
|
|
166
|
+
_this3.removeItem(newItem, Array.from(_this3.selectedItemsList.children).indexOf(newItem));
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
newItem.appendChild(removeBtn);
|
|
170
|
+
|
|
171
|
+
this.selectedItemsList.appendChild(newItem);
|
|
172
|
+
this.selectedItems.push(item);
|
|
124
173
|
}
|
|
125
|
-
}
|
|
174
|
+
}, {
|
|
175
|
+
key: 'removeHighlight',
|
|
176
|
+
value: function removeHighlight() {
|
|
177
|
+
var items = this.suggestionsBox.getElementsByClassName(this.baseClassName + '__suggestion-btn');
|
|
178
|
+
|
|
179
|
+
[].forEach.call(items, function (item) {
|
|
180
|
+
item.classList.remove('autocomplete-active');
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}, {
|
|
184
|
+
key: 'highlight',
|
|
185
|
+
value: function highlight(direction) {
|
|
186
|
+
var items = this.suggestionsBox.getElementsByClassName(this.baseClassName + '__suggestion-btn');
|
|
187
|
+
var focus = this.currentFocus;
|
|
188
|
+
|
|
189
|
+
if (direction === 'down') {
|
|
190
|
+
focus = focus >= items.length - 1 ? 0 : focus + 1;
|
|
191
|
+
} else {
|
|
192
|
+
focus = focus <= 0 ? items.length - 1 : focus - 1;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
this.setFocus(focus);
|
|
196
|
+
this.removeHighlight();
|
|
126
197
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
// Add the clicked suggestion to the selected items list
|
|
130
|
-
if (e.target && e.target.classList.contains('suggestion-btn')) {
|
|
131
|
-
addSelectedItem(e.target.textContent);
|
|
132
|
-
suggestionsBox.innerHTML = '';
|
|
133
|
-
multiSelectInput.value = '';
|
|
198
|
+
items[this.currentFocus].classList.add('autocomplete-active');
|
|
199
|
+
items[this.currentFocus].scrollIntoView({ block: 'nearest' });
|
|
134
200
|
}
|
|
135
|
-
}
|
|
136
|
-
|
|
201
|
+
}, {
|
|
202
|
+
key: 'selectHighlighted',
|
|
203
|
+
value: function selectHighlighted() {
|
|
204
|
+
var items = this.suggestionsBox.getElementsByClassName(this.baseClassName + '__suggestion-btn');
|
|
205
|
+
|
|
206
|
+
if (this.currentFocus > -1 && items[this.currentFocus]) {
|
|
207
|
+
this.addItem(items[this.currentFocus].textContent);
|
|
208
|
+
this.clearSuggestions();
|
|
209
|
+
this.input.value = '';
|
|
210
|
+
this.resetFocus();
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}]);
|
|
214
|
+
|
|
215
|
+
return MultiSelect;
|
|
216
|
+
}();
|
|
217
|
+
|
|
218
|
+
var multiSelectElements = document.querySelectorAll('.js-m-multi-select');
|
|
137
219
|
|
|
138
220
|
if (multiSelectElements) {
|
|
139
|
-
[].forEach.call(multiSelectElements,
|
|
221
|
+
[].forEach.call(multiSelectElements, function (el) {
|
|
222
|
+
return new MultiSelect(el);
|
|
223
|
+
});
|
|
140
224
|
}
|
package/package.json
CHANGED
package/src/components.js
CHANGED
|
@@ -1,134 +1,182 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import className from '../../assets/js/className';
|
|
2
|
+
|
|
3
|
+
class MultiSelect {
|
|
4
|
+
constructor(el) {
|
|
5
|
+
this.element = el;
|
|
6
|
+
this.baseClassName = 'm-multi-select';
|
|
7
|
+
this.currentFocus = -1;
|
|
8
|
+
this.input = this.element.querySelector(`.js-${this.baseClassName}__input`);
|
|
9
|
+
this.suggestionsBox = this.element.querySelector(`.js-${this.baseClassName}-suggestions-box`);
|
|
10
|
+
this.selectedItemsList = this.element.querySelector('.js-m-multi-select-selected-items');
|
|
11
|
+
this.selectedItems = [];
|
|
12
|
+
this.data = [];
|
|
13
|
+
|
|
14
|
+
this.getData();
|
|
15
|
+
this.attach();
|
|
16
|
+
}
|
|
5
17
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
18
|
+
getData() {
|
|
19
|
+
const id = this.input.getAttribute('data-multi-select-suggestions');
|
|
20
|
+
const el = document.getElementById(id);
|
|
9
21
|
|
|
10
|
-
|
|
22
|
+
if (!el) {
|
|
23
|
+
this.data = [];
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
11
26
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
if (!items.length) return false;
|
|
15
|
-
removeActive(items);
|
|
16
|
-
if (currentFocus >= items.length) currentFocus = 0;
|
|
17
|
-
if (currentFocus < 0) currentFocus = items.length - 1;
|
|
18
|
-
items[currentFocus].classList.add('autocomplete-active');
|
|
27
|
+
this.data = JSON.parse(el.textContent);
|
|
28
|
+
}
|
|
19
29
|
|
|
20
|
-
|
|
21
|
-
|
|
30
|
+
attach() {
|
|
31
|
+
this.input.addEventListener('input', this.onInput);
|
|
32
|
+
this.input.addEventListener('keydown', this.onKeyDown);
|
|
33
|
+
this.suggestionsBox.addEventListener('click', this.onClick);
|
|
34
|
+
}
|
|
22
35
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
for (let i = 0; i < items.length; i+=1) {
|
|
26
|
-
items[i].classList.remove('autocomplete-active');
|
|
36
|
+
setFocus(index) {
|
|
37
|
+
this.currentFocus = index;
|
|
27
38
|
}
|
|
28
|
-
}
|
|
29
39
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const newItem = document.createElement('li');
|
|
34
|
-
newItem.textContent = item + ' ';
|
|
35
|
-
newItem.classList.add(`${namespace}a-tag`);
|
|
36
|
-
newItem.classList.add(`${namespace}m-multi-select__tag`);
|
|
37
|
-
|
|
38
|
-
const removeBtn = document.createElement('button');
|
|
39
|
-
removeBtn.classList.add(`${namespace}m-multi-select-selected-items__remove-btn`);
|
|
40
|
-
|
|
41
|
-
const buttonTextContainer = document.createElement('span');
|
|
42
|
-
buttonTextContainer.classList.add('u-visuallyhidden');
|
|
43
|
-
removeBtn.appendChild(buttonTextContainer);
|
|
44
|
-
buttonTextContainer.textContent ='Ta bort ' + item; // Accessibility label for screen readers
|
|
45
|
-
|
|
46
|
-
// Event listener for removing the selected item
|
|
47
|
-
removeBtn.addEventListener('click', function () {
|
|
48
|
-
removeItem(newItem, Array.from(selectedItemsList.children).indexOf(newItem));
|
|
49
|
-
});
|
|
50
|
-
newItem.appendChild(removeBtn);
|
|
51
|
-
selectedItemsList.appendChild(newItem);
|
|
52
|
-
}
|
|
40
|
+
resetFocus() {
|
|
41
|
+
this.setFocus(-1);
|
|
42
|
+
}
|
|
53
43
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
selectedItemsList.removeChild(item);
|
|
44
|
+
clearSuggestions() {
|
|
45
|
+
this.suggestionsBox.innerHTML = '';
|
|
46
|
+
}
|
|
58
47
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
remainingItems[index].getElementsByTagName('button')[0].focus();
|
|
64
|
-
} else {
|
|
65
|
-
remainingItems[remainingItems.length - 1].getElementsByTagName('button')[0].focus();
|
|
66
|
-
}
|
|
67
|
-
} else {
|
|
68
|
-
multiSelectInput.focus();
|
|
48
|
+
filterData(query) {
|
|
49
|
+
return this.data
|
|
50
|
+
.filter((item) => item.name.toLowerCase().startsWith(query.toLowerCase()))
|
|
51
|
+
.filter((item) => !this.selectedItems.includes(item.name));
|
|
69
52
|
}
|
|
70
|
-
}
|
|
71
53
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
54
|
+
populateSuggestions(suggestions) {
|
|
55
|
+
const cls = className(`${this.baseClassName}__suggestion-btn`);
|
|
56
|
+
this.suggestionsBox.innerHTML = suggestions.map((item) => `<button class='${cls}' tabindex='0'>${item.name}</button>`).join('');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
onInput = () => {
|
|
60
|
+
const { value } = this.input;
|
|
76
61
|
|
|
77
|
-
// Event listener for input changes in the search field
|
|
78
|
-
multiSelectInput.addEventListener('input', function () {
|
|
79
|
-
const value = this.value;
|
|
80
62
|
// Clear suggestions if less than 2 characters are typed
|
|
81
63
|
if (value.length < 2) {
|
|
82
|
-
|
|
64
|
+
this.clearSuggestions();
|
|
65
|
+
|
|
83
66
|
return;
|
|
84
67
|
}
|
|
85
68
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
setActive(items);
|
|
105
|
-
// Navigate up in the suggestions list
|
|
106
|
-
} else if (e.keyCode == 38) {
|
|
107
|
-
currentFocus = (currentFocus - 1 + items.length) % items.length;
|
|
108
|
-
setActive(items);
|
|
109
|
-
// Handle Enter key to select a focused item
|
|
110
|
-
} else if (e.keyCode == 13) {
|
|
111
|
-
e.preventDefault();
|
|
112
|
-
if (currentFocus > -1 && items[currentFocus]) {
|
|
113
|
-
addSelectedItem(items[currentFocus].textContent);
|
|
114
|
-
suggestionsBox.innerHTML = '';
|
|
115
|
-
multiSelectInput.value = '';
|
|
116
|
-
currentFocus = -1;
|
|
69
|
+
const suggestions = this.filterData(value);
|
|
70
|
+
|
|
71
|
+
this.populateSuggestions(suggestions);
|
|
72
|
+
this.resetFocus();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
removeItem(item, index) {
|
|
76
|
+
const selectedItemsList = this.element.querySelector('.js-m-multi-select-selected-items');
|
|
77
|
+
selectedItemsList.removeChild(item);
|
|
78
|
+
|
|
79
|
+
const remainingItems = selectedItemsList.getElementsByTagName('div');
|
|
80
|
+
|
|
81
|
+
// Focus management: set focus to the next item, or the search input if no items left
|
|
82
|
+
if (remainingItems.length > 0) {
|
|
83
|
+
if (index < remainingItems.length) {
|
|
84
|
+
remainingItems[index].getElementsByTagName('button')[0].focus();
|
|
85
|
+
} else {
|
|
86
|
+
remainingItems[remainingItems.length - 1].getElementsByTagName('button')[0].focus();
|
|
117
87
|
}
|
|
88
|
+
} else {
|
|
89
|
+
this.input.focus();
|
|
118
90
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
91
|
+
|
|
92
|
+
this.selectedItems = this.selectedItems
|
|
93
|
+
.filter((name) => name !== item.firstChild.textContent.trim());
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
addItem(item) {
|
|
97
|
+
const newItem = document.createElement('li');
|
|
98
|
+
newItem.textContent = `${item} `;
|
|
99
|
+
newItem.classList.add(className('a-tag'));
|
|
100
|
+
newItem.classList.add(className(`${this.baseClassName}__tag`));
|
|
101
|
+
|
|
102
|
+
const removeBtn = document.createElement('button');
|
|
103
|
+
removeBtn.classList.add(className(`${this.baseClassName}-selected-items__remove-btn`));
|
|
104
|
+
|
|
105
|
+
const buttonTextContainer = document.createElement('span');
|
|
106
|
+
buttonTextContainer.classList.add('u-visuallyhidden');
|
|
107
|
+
removeBtn.appendChild(buttonTextContainer);
|
|
108
|
+
buttonTextContainer.textContent = `Ta bort ${item}`; // Accessibility label for screen readers
|
|
109
|
+
|
|
110
|
+
// Event listener for removing the selected item
|
|
111
|
+
removeBtn.addEventListener('click', () => {
|
|
112
|
+
this.removeItem(newItem, Array.from(this.selectedItemsList.children).indexOf(newItem));
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
newItem.appendChild(removeBtn);
|
|
116
|
+
|
|
117
|
+
this.selectedItemsList.appendChild(newItem);
|
|
118
|
+
this.selectedItems.push(item);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
removeHighlight() {
|
|
122
|
+
const items = this.suggestionsBox.getElementsByClassName(`${this.baseClassName}__suggestion-btn`);
|
|
123
|
+
|
|
124
|
+
[].forEach.call(items, (item) => {
|
|
125
|
+
item.classList.remove('autocomplete-active');
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
highlight(direction) {
|
|
130
|
+
const items = this.suggestionsBox.getElementsByClassName(`${this.baseClassName}__suggestion-btn`);
|
|
131
|
+
let focus = this.currentFocus;
|
|
132
|
+
|
|
133
|
+
if (direction === 'down') {
|
|
134
|
+
focus = (focus >= items.length - 1) ? 0 : focus + 1;
|
|
135
|
+
} else {
|
|
136
|
+
focus = (focus <= 0) ? items.length - 1 : focus - 1;
|
|
128
137
|
}
|
|
129
|
-
|
|
138
|
+
|
|
139
|
+
this.setFocus(focus);
|
|
140
|
+
this.removeHighlight();
|
|
141
|
+
|
|
142
|
+
items[this.currentFocus].classList.add('autocomplete-active');
|
|
143
|
+
items[this.currentFocus].scrollIntoView({ block: 'nearest' });
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
selectHighlighted() {
|
|
147
|
+
const items = this.suggestionsBox.getElementsByClassName(`${this.baseClassName}__suggestion-btn`);
|
|
148
|
+
|
|
149
|
+
if (this.currentFocus > -1 && items[this.currentFocus]) {
|
|
150
|
+
this.addItem(items[this.currentFocus].textContent);
|
|
151
|
+
this.clearSuggestions();
|
|
152
|
+
this.input.value = '';
|
|
153
|
+
this.resetFocus();
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
onKeyDown = (e) => {
|
|
158
|
+
if (e.keyCode === 40) {
|
|
159
|
+
this.highlight('down');
|
|
160
|
+
} else if (e.keyCode === 38) {
|
|
161
|
+
this.highlight('up');
|
|
162
|
+
} else if (e.keyCode === 13) {
|
|
163
|
+
e.preventDefault();
|
|
164
|
+
|
|
165
|
+
this.selectHighlighted();
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
onClick = (e) => {
|
|
170
|
+
if (e.target.classList.contains(className(`${this.baseClassName}__suggestion-btn`))) {
|
|
171
|
+
this.addItem(e.target.textContent);
|
|
172
|
+
this.clearSuggestions();
|
|
173
|
+
this.input.value = '';
|
|
174
|
+
}
|
|
175
|
+
}
|
|
130
176
|
}
|
|
131
177
|
|
|
178
|
+
const multiSelectElements = document.querySelectorAll('.js-m-multi-select');
|
|
179
|
+
|
|
132
180
|
if (multiSelectElements) {
|
|
133
|
-
[].forEach.call(multiSelectElements,
|
|
181
|
+
[].forEach.call(multiSelectElements, (el) => new MultiSelect(el));
|
|
134
182
|
}
|