@internetstiftelsen/styleguide 4.0.12-beta.0.5 → 4.0.13

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.
@@ -72,4 +72,6 @@ require('./assets/js/utmGenerator');
72
72
 
73
73
  require('./assets/js/textToggle');
74
74
 
75
- require('./assets/js/iconToggle');
75
+ require('./assets/js/iconToggle');
76
+
77
+ require('./molecules/multi-select/multi-select');
@@ -1,140 +1,269 @@
1
1
  'use strict';
2
2
 
3
- /* eslint-disable */
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
- if (multiSelectElements) {
9
- namespace = getComputedStyle(multiSelectElements[0], ':before').content.replace(/["']/g, '');
10
- }
11
-
12
- var currentFocus = -1; // Tracks the currently focused item in the suggestions
13
-
14
- // Highlight the active (focused) suggestion
15
- function setActive(items) {
16
- if (!items.length) return false;
17
- removeActive(items);
18
- if (currentFocus >= items.length) currentFocus = 0;
19
- if (currentFocus < 0) currentFocus = items.length - 1;
20
- items[currentFocus].classList.add('autocomplete-active');
21
-
22
- return items;
23
- }
24
-
25
- // Remove highlighting from all suggestions
26
- function removeActive(items) {
27
- for (var i = 0; i < items.length; i += 1) {
28
- items[i].classList.remove('autocomplete-active');
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 _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
12
+
13
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
14
+
15
+ var MultiSelect = function () {
16
+ function MultiSelect(el) {
17
+ var _this = this;
18
+
19
+ _classCallCheck(this, MultiSelect);
20
+
21
+ this.onInput = function () {
22
+ var value = _this.input.value;
23
+
24
+ // Clear suggestions if less than 2 characters are typed
25
+
26
+ if (value.length < 2) {
27
+ _this.clearSuggestions();
28
+
29
+ return;
30
+ }
31
+
32
+ var suggestions = _this.filterData(value);
33
+
34
+ _this.populateSuggestions(suggestions);
35
+ _this.resetFocus();
36
+ };
37
+
38
+ this.onKeyDown = function (e) {
39
+ if (e.keyCode === 40) {
40
+ _this.highlight('down');
41
+ } else if (e.keyCode === 38) {
42
+ _this.highlight('up');
43
+ } else if (e.keyCode === 13) {
44
+ e.preventDefault();
45
+
46
+ _this.selectHighlighted();
47
+ }
48
+ };
49
+
50
+ this.onClick = function (e) {
51
+ if (e.target.classList.contains((0, _className2.default)(_this.baseClassName + '__suggestion-btn'))) {
52
+ _this.addItem(_this.data.find(function (d) {
53
+ return d.value === e.target.value;
54
+ }));
55
+ _this.clearSuggestions();
56
+ _this.input.value = '';
57
+ }
58
+ };
59
+
60
+ this.element = el;
61
+ this.baseClassName = 'm-multi-select';
62
+ this.currentFocus = -1;
63
+ this.name = this.element.getAttribute('data-multi-select-name');
64
+ this.input = this.element.querySelector('.js-' + this.baseClassName + '__input');
65
+ this.suggestionsBox = this.element.querySelector('.js-' + this.baseClassName + '-suggestions-box');
66
+ this.selectedItemsList = this.element.querySelector('.js-m-multi-select-selected-items');
67
+ this.selectedItems = [];
68
+ this.data = [];
69
+
70
+ this.getData();
71
+ this.attach();
29
72
  }
30
- }
31
-
32
- // Add a selected item to the list of selected items
33
- function addSelectedItem(item) {
34
- var selectedItemsList = document.querySelector('.js-m-multi-select-selected-items');
35
- var newItem = document.createElement('li');
36
- newItem.textContent = item + ' ';
37
- newItem.classList.add(namespace + 'a-tag');
38
- newItem.classList.add(namespace + 'm-multi-select__tag');
39
-
40
- var removeBtn = document.createElement('button');
41
- removeBtn.classList.add(namespace + 'm-multi-select-selected-items__remove-btn');
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();
73
+
74
+ _createClass(MultiSelect, [{
75
+ key: 'getData',
76
+ value: function getData() {
77
+ var id = this.input.getAttribute('data-multi-select-suggestions');
78
+ var el = document.getElementById(id);
79
+
80
+ if (!el) {
81
+ this.data = [];
82
+ return;
83
+ }
84
+
85
+ this.data = JSON.parse(el.textContent);
68
86
  }
69
- } else {
70
- multiSelectInput.focus();
71
- }
72
- }
73
-
74
- function setup(multiSelectElement) {
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;
87
+ }, {
88
+ key: 'attach',
89
+ value: function attach() {
90
+ this.input.addEventListener('input', this.onInput);
91
+ this.input.addEventListener('keydown', this.onKeyDown);
92
+ this.suggestionsBox.addEventListener('click', this.onClick);
86
93
  }
94
+ }, {
95
+ key: 'setFocus',
96
+ value: function setFocus(index) {
97
+ this.currentFocus = index;
98
+ }
99
+ }, {
100
+ key: 'resetFocus',
101
+ value: function resetFocus() {
102
+ this.setFocus(-1);
103
+ }
104
+ }, {
105
+ key: 'clearSuggestions',
106
+ value: function clearSuggestions() {
107
+ this.suggestionsBox.innerHTML = '';
108
+ }
109
+ }, {
110
+ key: 'addSuggestions',
111
+ value: function addSuggestions(suggestions) {
112
+ var _this2 = this;
87
113
 
88
- // Define JSON
89
- var suggestions = document.getElementById(suggestionsData).textContent;
90
- suggestions = JSON.parse(suggestions);
91
-
92
- // Filter suggestions based on the input value
93
- var filtered = suggestions.filter(function (item) {
94
- return item.name.toLowerCase().startsWith(value.toLowerCase());
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
- });
114
+ this.data = [].concat(_toConsumableArray(this.data), _toConsumableArray(suggestions.filter(function (s) {
115
+ return !_this2.data.find(function (d) {
116
+ return d.value === s.value;
117
+ });
118
+ })));
119
+ }
120
+ }, {
121
+ key: 'filterData',
122
+ value: function filterData(query) {
123
+ var _this3 = this;
124
+
125
+ return this.data.filter(function (item) {
126
+ return item.name.toLowerCase().startsWith(query.toLowerCase());
127
+ }).filter(function (item) {
128
+ return !_this3.selectedItems.includes(item.name);
129
+ });
130
+ }
131
+ }, {
132
+ key: 'populateSuggestions',
133
+ value: function populateSuggestions(suggestions) {
134
+ var cls = (0, _className2.default)(this.baseClassName + '__suggestion-btn');
135
+ this.suggestionsBox.innerHTML = suggestions.map(function (item) {
136
+ return '<button class=\'' + cls + '\' tabindex=\'0\' value="' + item.value + '">' + item.name + '</button>';
137
+ }).join('');
138
+ }
139
+ }, {
140
+ key: 'removeItem',
141
+ value: function removeItem(item) {
142
+ var node = this.element.querySelector('.js-m-multi-select-selected-items li[data-value="' + item.value + '"]');
103
143
 
104
- // Event listener for keydown events for navigation and selection in the suggestions box
105
- multiSelectInput.addEventListener('keydown', function (e) {
106
- var items = suggestionsBox.getElementsByClassName(namespace + 'm-multi-select__suggestion-btn');
107
- // Navigate down in the suggestions list
108
- if (e.keyCode == 40) {
109
- currentFocus = (currentFocus + 1) % items.length;
110
- setActive(items);
111
- // Navigate up in the suggestions list
112
- } else if (e.keyCode == 38) {
113
- currentFocus = (currentFocus - 1 + items.length) % items.length;
114
- setActive(items);
115
- // Handle Enter key to select a focused item
116
- } else if (e.keyCode == 13) {
117
- e.preventDefault();
118
- if (currentFocus > -1 && items[currentFocus]) {
119
- addSelectedItem(items[currentFocus].textContent);
120
- suggestionsBox.innerHTML = '';
121
- multiSelectInput.value = '';
122
- currentFocus = -1;
144
+ if (!node) {
145
+ return;
123
146
  }
147
+
148
+ var parent = node.closest('.js-m-multi-select-selected-items');
149
+ var index = Array.prototype.indexOf.call(parent.children, node);
150
+
151
+ node.remove();
152
+
153
+ var remainingItems = parent.getElementsByTagName('li');
154
+
155
+ // Focus management: set focus to the next item, or the search input if no items left
156
+ if (remainingItems.length > 0) {
157
+ if (index < remainingItems.length) {
158
+ remainingItems[index].getElementsByTagName('button')[0].focus();
159
+ } else {
160
+ remainingItems[remainingItems.length - 1].getElementsByTagName('button')[0].focus();
161
+ }
162
+ } else {
163
+ this.input.focus();
164
+ }
165
+
166
+ this.selectedItems = this.selectedItems.filter(function (i) {
167
+ return i.value !== item.value;
168
+ });
169
+
170
+ var itemInput = this.element.querySelector('input[value="' + item.value + '"]');
171
+ itemInput.remove();
124
172
  }
125
- });
173
+ }, {
174
+ key: 'addItem',
175
+ value: function addItem(item) {
176
+ var _this4 = this;
177
+
178
+ if (!item) {
179
+ return;
180
+ }
181
+
182
+ var newItem = document.createElement('li');
183
+ newItem.textContent = item.name + ' ';
184
+ newItem.setAttribute('data-value', item.value);
185
+ newItem.classList.add((0, _className2.default)('a-tag'));
186
+ newItem.classList.add((0, _className2.default)(this.baseClassName + '__tag'));
187
+
188
+ var removeBtn = document.createElement('button');
189
+ removeBtn.classList.add((0, _className2.default)(this.baseClassName + '-selected-items__remove-btn'));
190
+
191
+ var buttonTextContainer = document.createElement('span');
192
+ buttonTextContainer.classList.add('u-visuallyhidden');
193
+ removeBtn.appendChild(buttonTextContainer);
194
+ buttonTextContainer.textContent = 'Ta bort ' + item.name; // Accessibility label for screen readers
195
+
196
+ // Event listener for removing the selected item
197
+ removeBtn.addEventListener('click', function () {
198
+ _this4.removeItem(item);
199
+ });
200
+
201
+ newItem.appendChild(removeBtn);
202
+
203
+ this.selectedItemsList.appendChild(newItem);
204
+ this.selectedItems.push(item);
205
+
206
+ var itemInput = document.createElement('input');
126
207
 
127
- // Event listener for the suggestions box
128
- suggestionsBox.addEventListener('click', function (e) {
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 = '';
208
+ itemInput.type = 'hidden';
209
+ itemInput.name = this.name + '[]';
210
+ itemInput.value = item.value;
211
+
212
+ this.element.appendChild(itemInput);
134
213
  }
135
- });
136
- }
214
+ }, {
215
+ key: 'removeHighlight',
216
+ value: function removeHighlight() {
217
+ var items = this.suggestionsBox.getElementsByClassName(this.baseClassName + '__suggestion-btn');
218
+
219
+ [].forEach.call(items, function (item) {
220
+ item.classList.remove('autocomplete-active');
221
+ });
222
+ }
223
+ }, {
224
+ key: 'highlight',
225
+ value: function highlight(direction) {
226
+ var items = this.suggestionsBox.getElementsByClassName(this.baseClassName + '__suggestion-btn');
227
+ var focus = this.currentFocus;
228
+
229
+ if (direction === 'down') {
230
+ focus = focus >= items.length - 1 ? 0 : focus + 1;
231
+ } else {
232
+ focus = focus <= 0 ? items.length - 1 : focus - 1;
233
+ }
234
+
235
+ this.setFocus(focus);
236
+ this.removeHighlight();
237
+
238
+ items[this.currentFocus].classList.add('autocomplete-active');
239
+ items[this.currentFocus].scrollIntoView({ block: 'nearest' });
240
+ }
241
+ }, {
242
+ key: 'selectHighlighted',
243
+ value: function selectHighlighted() {
244
+ var items = this.suggestionsBox.getElementsByClassName(this.baseClassName + '__suggestion-btn');
245
+
246
+ if (this.currentFocus > -1 && items[this.currentFocus]) {
247
+ var item = items[this.currentFocus];
248
+
249
+ this.addItem(this.data.find(function (d) {
250
+ return d.value === item.value;
251
+ }));
252
+
253
+ this.clearSuggestions();
254
+ this.input.value = '';
255
+ this.resetFocus();
256
+ }
257
+ }
258
+ }]);
259
+
260
+ return MultiSelect;
261
+ }();
262
+
263
+ var multiSelectElements = document.querySelectorAll('.js-m-multi-select');
137
264
 
138
265
  if (multiSelectElements) {
139
- [].forEach.call(multiSelectElements, setup);
266
+ [].forEach.call(multiSelectElements, function (el) {
267
+ el.multiSelect = new MultiSelect(el);
268
+ });
140
269
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@internetstiftelsen/styleguide",
3
- "version": "4.0.12-beta.0.5",
3
+ "version": "4.0.13",
4
4
  "main": "dist/components.js",
5
5
  "ports": {
6
6
  "fractal": "3000"
package/src/components.js CHANGED
@@ -35,4 +35,4 @@ import './atoms/range/range';
35
35
  import './assets/js/utmGenerator';
36
36
  import './assets/js/textToggle';
37
37
  import './assets/js/iconToggle';
38
- // import './molecules/multi-select/multi-select';
38
+ import './molecules/multi-select/multi-select';
@@ -9,6 +9,10 @@
9
9
  content: $namespace;
10
10
  }
11
11
 
12
+ @include e(search) {
13
+ position: relative;
14
+ }
15
+
12
16
  @include e(suggestions-box) {
13
17
  position: absolute;
14
18
  border-top: none;
@@ -1,134 +1,219 @@
1
- /* eslint-disable */
2
- const className = 'm-multi-select';
3
- const multiSelectElements = document.querySelectorAll(`.js-${className}`);
4
- let namespace;
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.name = this.element.getAttribute('data-multi-select-name');
9
+ this.input = this.element.querySelector(`.js-${this.baseClassName}__input`);
10
+ this.suggestionsBox = this.element.querySelector(`.js-${this.baseClassName}-suggestions-box`);
11
+ this.selectedItemsList = this.element.querySelector('.js-m-multi-select-selected-items');
12
+ this.selectedItems = [];
13
+ this.data = [];
14
+
15
+ this.getData();
16
+ this.attach();
17
+ }
5
18
 
6
- if( multiSelectElements ) {
7
- namespace = getComputedStyle(multiSelectElements[0], ':before').content.replace(/["']/g, '');
8
- }
19
+ getData() {
20
+ const id = this.input.getAttribute('data-multi-select-suggestions');
21
+ const el = document.getElementById(id);
9
22
 
10
- let currentFocus = -1; // Tracks the currently focused item in the suggestions
23
+ if (!el) {
24
+ this.data = [];
25
+ return;
26
+ }
11
27
 
12
- // Highlight the active (focused) suggestion
13
- function setActive(items) {
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');
28
+ this.data = JSON.parse(el.textContent);
29
+ }
19
30
 
20
- return items;
21
- }
31
+ attach() {
32
+ this.input.addEventListener('input', this.onInput);
33
+ this.input.addEventListener('keydown', this.onKeyDown);
34
+ this.suggestionsBox.addEventListener('click', this.onClick);
35
+ }
22
36
 
23
- // Remove highlighting from all suggestions
24
- function removeActive(items) {
25
- for (let i = 0; i < items.length; i+=1) {
26
- items[i].classList.remove('autocomplete-active');
37
+ setFocus(index) {
38
+ this.currentFocus = index;
27
39
  }
28
- }
29
40
 
30
- // Add a selected item to the list of selected items
31
- function addSelectedItem(item) {
32
- const selectedItemsList = document.querySelector('.js-m-multi-select-selected-items');
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
- }
41
+ resetFocus() {
42
+ this.setFocus(-1);
43
+ }
53
44
 
54
- // Remove an item and manage focus appropriately
55
- function removeItem(item, index) {
56
- const selectedItemsList = document.querySelector('.js-m-multi-select-selected-items');
57
- selectedItemsList.removeChild(item);
45
+ clearSuggestions() {
46
+ this.suggestionsBox.innerHTML = '';
47
+ }
58
48
 
59
- let remainingItems = selectedItemsList.getElementsByTagName('div');
60
- // Focus management: set focus to the next item, or the search input if no items left
61
- if (remainingItems.length > 0) {
62
- if (index < remainingItems.length) {
63
- remainingItems[index].getElementsByTagName('button')[0].focus();
64
- } else {
65
- remainingItems[remainingItems.length - 1].getElementsByTagName('button')[0].focus();
66
- }
67
- } else {
68
- multiSelectInput.focus();
49
+ addSuggestions(suggestions) {
50
+ this.data = [
51
+ ...this.data,
52
+ ...suggestions.filter((s) => !this.data.find((d) => d.value === s.value)),
53
+ ];
54
+ }
55
+
56
+ filterData(query) {
57
+ return this.data
58
+ .filter((item) => item.name.toLowerCase().startsWith(query.toLowerCase()))
59
+ .filter((item) => !this.selectedItems.includes(item.name));
60
+ }
61
+
62
+ populateSuggestions(suggestions) {
63
+ const cls = className(`${this.baseClassName}__suggestion-btn`);
64
+ this.suggestionsBox.innerHTML = suggestions.map((item) => `<button class='${cls}' tabindex='0' value="${item.value}">${item.name}</button>`).join('');
69
65
  }
70
- }
71
66
 
72
- function setup(multiSelectElement) {
73
- const multiSelectInput = multiSelectElement.querySelector(`.js-${className}__input`);
74
- const suggestionsBox = multiSelectElement.querySelector(`.js-${className}-suggestions-box`);
75
- const suggestionsData = multiSelectInput.getAttribute('data-multi-select-suggestions');
67
+ onInput = () => {
68
+ const { value } = this.input;
76
69
 
77
- // Event listener for input changes in the search field
78
- multiSelectInput.addEventListener('input', function () {
79
- const value = this.value;
80
70
  // Clear suggestions if less than 2 characters are typed
81
71
  if (value.length < 2) {
82
- suggestionsBox.innerHTML = '';
72
+ this.clearSuggestions();
73
+
83
74
  return;
84
75
  }
85
76
 
86
- // Define JSON
87
- let suggestions = document.getElementById(suggestionsData).textContent;
88
- suggestions = JSON.parse(suggestions);
77
+ const suggestions = this.filterData(value);
89
78
 
90
- // Filter suggestions based on the input value
91
- const filtered = suggestions.filter(item => item.name.toLowerCase().startsWith(value.toLowerCase()));
92
- // Populate the suggestions box with the filtered results
93
- suggestionsBox.innerHTML = filtered.map(item => `<button class='${namespace}m-multi-select__suggestion-btn' tabindex='0'>${item.name}</button>`).join('');
94
- // Reset the current focus
95
- currentFocus = -1;
96
- });
79
+ this.populateSuggestions(suggestions);
80
+ this.resetFocus();
81
+ }
97
82
 
98
- // Event listener for keydown events for navigation and selection in the suggestions box
99
- multiSelectInput.addEventListener('keydown', function (e) {
100
- let items = suggestionsBox.getElementsByClassName(`${namespace}m-multi-select__suggestion-btn`);
101
- // Navigate down in the suggestions list
102
- if (e.keyCode == 40) {
103
- currentFocus = (currentFocus + 1) % items.length;
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;
83
+ removeItem(item) {
84
+ const node = this.element.querySelector(`.js-m-multi-select-selected-items li[data-value="${item.value}"]`);
85
+
86
+ if (!node) {
87
+ return;
88
+ }
89
+
90
+ const parent = node.closest('.js-m-multi-select-selected-items');
91
+ const index = Array.prototype.indexOf.call(parent.children, node);
92
+
93
+ node.remove();
94
+
95
+ const remainingItems = parent.getElementsByTagName('li');
96
+
97
+ // Focus management: set focus to the next item, or the search input if no items left
98
+ if (remainingItems.length > 0) {
99
+ if (index < remainingItems.length) {
100
+ remainingItems[index].getElementsByTagName('button')[0].focus();
101
+ } else {
102
+ remainingItems[remainingItems.length - 1].getElementsByTagName('button')[0].focus();
117
103
  }
104
+ } else {
105
+ this.input.focus();
118
106
  }
119
- });
120
107
 
121
- // Event listener for the suggestions box
122
- suggestionsBox.addEventListener('click', function (e) {
123
- // Add the clicked suggestion to the selected items list
124
- if (e.target && e.target.classList.contains('suggestion-btn')) {
125
- addSelectedItem(e.target.textContent);
126
- suggestionsBox.innerHTML = '';
127
- multiSelectInput.value = '';
108
+ this.selectedItems = this.selectedItems
109
+ .filter((i) => i.value !== item.value);
110
+
111
+ const itemInput = this.element.querySelector(`input[value="${item.value}"]`);
112
+ itemInput.remove();
113
+ }
114
+
115
+ addItem(item) {
116
+ if (!item) {
117
+ return;
128
118
  }
129
- });
119
+
120
+ const newItem = document.createElement('li');
121
+ newItem.textContent = `${item.name} `;
122
+ newItem.setAttribute('data-value', item.value);
123
+ newItem.classList.add(className('a-tag'));
124
+ newItem.classList.add(className(`${this.baseClassName}__tag`));
125
+
126
+ const removeBtn = document.createElement('button');
127
+ removeBtn.classList.add(className(`${this.baseClassName}-selected-items__remove-btn`));
128
+
129
+ const buttonTextContainer = document.createElement('span');
130
+ buttonTextContainer.classList.add('u-visuallyhidden');
131
+ removeBtn.appendChild(buttonTextContainer);
132
+ buttonTextContainer.textContent = `Ta bort ${item.name}`; // Accessibility label for screen readers
133
+
134
+ // Event listener for removing the selected item
135
+ removeBtn.addEventListener('click', () => {
136
+ this.removeItem(item);
137
+ });
138
+
139
+ newItem.appendChild(removeBtn);
140
+
141
+ this.selectedItemsList.appendChild(newItem);
142
+ this.selectedItems.push(item);
143
+
144
+ const itemInput = document.createElement('input');
145
+
146
+ itemInput.type = 'hidden';
147
+ itemInput.name = `${this.name}[]`;
148
+ itemInput.value = item.value;
149
+
150
+ this.element.appendChild(itemInput);
151
+ }
152
+
153
+ removeHighlight() {
154
+ const items = this.suggestionsBox.getElementsByClassName(`${this.baseClassName}__suggestion-btn`);
155
+
156
+ [].forEach.call(items, (item) => {
157
+ item.classList.remove('autocomplete-active');
158
+ });
159
+ }
160
+
161
+ highlight(direction) {
162
+ const items = this.suggestionsBox.getElementsByClassName(`${this.baseClassName}__suggestion-btn`);
163
+ let focus = this.currentFocus;
164
+
165
+ if (direction === 'down') {
166
+ focus = (focus >= items.length - 1) ? 0 : focus + 1;
167
+ } else {
168
+ focus = (focus <= 0) ? items.length - 1 : focus - 1;
169
+ }
170
+
171
+ this.setFocus(focus);
172
+ this.removeHighlight();
173
+
174
+ items[this.currentFocus].classList.add('autocomplete-active');
175
+ items[this.currentFocus].scrollIntoView({ block: 'nearest' });
176
+ }
177
+
178
+ selectHighlighted() {
179
+ const items = this.suggestionsBox.getElementsByClassName(`${this.baseClassName}__suggestion-btn`);
180
+
181
+ if (this.currentFocus > -1 && items[this.currentFocus]) {
182
+ const item = items[this.currentFocus];
183
+
184
+ this.addItem(this.data.find((d) => d.value === item.value));
185
+
186
+ this.clearSuggestions();
187
+ this.input.value = '';
188
+ this.resetFocus();
189
+ }
190
+ }
191
+
192
+ onKeyDown = (e) => {
193
+ if (e.keyCode === 40) {
194
+ this.highlight('down');
195
+ } else if (e.keyCode === 38) {
196
+ this.highlight('up');
197
+ } else if (e.keyCode === 13) {
198
+ e.preventDefault();
199
+
200
+ this.selectHighlighted();
201
+ }
202
+ }
203
+
204
+ onClick = (e) => {
205
+ if (e.target.classList.contains(className(`${this.baseClassName}__suggestion-btn`))) {
206
+ this.addItem(this.data.find((d) => d.value === e.target.value));
207
+ this.clearSuggestions();
208
+ this.input.value = '';
209
+ }
210
+ }
130
211
  }
131
212
 
213
+ const multiSelectElements = document.querySelectorAll('.js-m-multi-select');
214
+
132
215
  if (multiSelectElements) {
133
- [].forEach.call(multiSelectElements, setup);
216
+ [].forEach.call(multiSelectElements, (el) => {
217
+ el.multiSelect = new MultiSelect(el);
218
+ });
134
219
  }