slim-select 2.3.2 → 2.4.0
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/helpers.d.ts +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/render.d.ts +2 -1
- package/dist/settings.d.ts +1 -0
- package/dist/slimselect.cjs.js +50 -11
- package/dist/slimselect.css +1 -1
- package/dist/slimselect.css.map +1 -1
- package/dist/slimselect.es.js +50 -11
- package/dist/slimselect.global.js +50 -11
- package/dist/slimselect.js +50 -11
- package/dist/slimselect.min.js +1 -1
- package/dist/slimselect.umd.js +50 -11
- package/dist/slimselect.umd.min.js +1 -1
- package/package.json +14 -13
- package/src/slim-select/helpers.ts +12 -2
- package/src/slim-select/index.ts +32 -4
- package/src/slim-select/render.ts +28 -10
- package/src/slim-select/settings.ts +1 -0
- package/src/slim-select/slimselect.scss +1 -0
- package/src/vue/dist/slim-select/helpers.d.ts +1 -1
- package/src/vue/dist/slim-select/index.d.ts +2 -1
- package/src/vue/dist/slim-select/render.d.ts +2 -1
- package/src/vue/dist/slim-select/settings.d.ts +1 -0
- package/src/vue/dist/slimselectvue.es.js +50 -11
- package/src/vue/dist/slimselectvue.global.js +50 -11
- package/src/vue/dist/slimselectvue.ssr.js +50 -11
- package/src/vue/dist/vue/slimselect.vue.d.ts +5 -2
- package/src/vue/package.json +2 -1
|
@@ -127,6 +127,7 @@ export default class Render {
|
|
|
127
127
|
|
|
128
128
|
// Add classes and styles to main/content
|
|
129
129
|
this.updateClassStyles()
|
|
130
|
+
this.updateAriaAttributes()
|
|
130
131
|
|
|
131
132
|
// Add content to the content location settings
|
|
132
133
|
this.settings.contentLocation.appendChild(this.content.main)
|
|
@@ -155,6 +156,7 @@ export default class Render {
|
|
|
155
156
|
|
|
156
157
|
// Add class to main container
|
|
157
158
|
this.main.main.classList.add(this.settings.openPosition === 'up' ? this.classes.openAbove : this.classes.openBelow)
|
|
159
|
+
this.main.main.setAttribute('aria-expanded', 'true')
|
|
158
160
|
|
|
159
161
|
// move the content in to the right location
|
|
160
162
|
this.moveContent()
|
|
@@ -173,6 +175,7 @@ export default class Render {
|
|
|
173
175
|
public close(): void {
|
|
174
176
|
this.main.main.classList.remove(this.classes.openAbove)
|
|
175
177
|
this.main.main.classList.remove(this.classes.openBelow)
|
|
178
|
+
this.main.main.setAttribute('aria-expanded', 'false')
|
|
176
179
|
this.content.main.classList.remove(this.classes.openAbove)
|
|
177
180
|
this.content.main.classList.remove(this.classes.openBelow)
|
|
178
181
|
this.main.arrow.path.setAttribute('d', this.classes.arrowClose)
|
|
@@ -211,23 +214,26 @@ export default class Render {
|
|
|
211
214
|
}
|
|
212
215
|
}
|
|
213
216
|
|
|
217
|
+
public updateAriaAttributes() {
|
|
218
|
+
this.main.main.role = 'combobox'
|
|
219
|
+
this.main.main.setAttribute('aria-haspopup', 'listbox')
|
|
220
|
+
this.main.main.setAttribute('aria-controls', this.content.main.id)
|
|
221
|
+
this.main.main.setAttribute('aria-expanded', 'false')
|
|
222
|
+
this.content.main.setAttribute('role', 'listbox')
|
|
223
|
+
// do an aria-labelledby here maybe
|
|
224
|
+
}
|
|
225
|
+
|
|
214
226
|
public mainDiv(): Main {
|
|
215
227
|
// Create main container
|
|
216
228
|
const main = document.createElement('div')
|
|
217
229
|
|
|
218
230
|
// Add id to data-id
|
|
219
231
|
main.dataset.id = this.settings.id
|
|
232
|
+
main.id = this.settings.id
|
|
220
233
|
|
|
221
234
|
// Set tabable to allow tabbing to the element
|
|
222
235
|
main.tabIndex = 0
|
|
223
236
|
|
|
224
|
-
// If main gets focus, open the content
|
|
225
|
-
main.onfocus = () => {
|
|
226
|
-
if (this.settings.triggerFocus) {
|
|
227
|
-
this.callbacks.open()
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
237
|
// Deal with keyboard events on the main div
|
|
232
238
|
// This is to allow for normal selecting
|
|
233
239
|
// when you may not have a search bar
|
|
@@ -243,6 +249,8 @@ export default class Render {
|
|
|
243
249
|
this.callbacks.close()
|
|
244
250
|
return true // Continue doing normal tabbing
|
|
245
251
|
case 'Enter':
|
|
252
|
+
case ' ':
|
|
253
|
+
this.callbacks.open()
|
|
246
254
|
const highlighted = this.content.list.querySelector('.' + this.classes.highlighted) as HTMLDivElement
|
|
247
255
|
if (highlighted) {
|
|
248
256
|
highlighted.click()
|
|
@@ -346,12 +354,17 @@ export default class Render {
|
|
|
346
354
|
}
|
|
347
355
|
}
|
|
348
356
|
|
|
349
|
-
public mainFocus(trigger: boolean): void {
|
|
357
|
+
public mainFocus(trigger: boolean, eventType: string | null): void {
|
|
350
358
|
if (!trigger) {
|
|
351
359
|
this.settings.triggerFocus = false
|
|
352
360
|
}
|
|
353
361
|
// Trigger focus but dont scroll to it
|
|
354
|
-
|
|
362
|
+
// Need for prevent refocus the element if event is not keyboard event.
|
|
363
|
+
// For example if event is mouse click or tachpad click this condition prevent refocus on element
|
|
364
|
+
// because click by mouse change focus position and not need return focus to element.
|
|
365
|
+
if (eventType !== 'click') {
|
|
366
|
+
this.main.main.focus({ preventScroll: true })
|
|
367
|
+
}
|
|
355
368
|
this.settings.triggerFocus = true
|
|
356
369
|
}
|
|
357
370
|
|
|
@@ -595,6 +608,7 @@ export default class Render {
|
|
|
595
608
|
|
|
596
609
|
// Add id to data-id
|
|
597
610
|
main.dataset.id = this.settings.id
|
|
611
|
+
main.id = this.settings.id
|
|
598
612
|
|
|
599
613
|
// Add search
|
|
600
614
|
const search = this.searchDiv()
|
|
@@ -685,6 +699,7 @@ export default class Render {
|
|
|
685
699
|
this.callbacks.close()
|
|
686
700
|
return false
|
|
687
701
|
case 'Enter':
|
|
702
|
+
case ' ':
|
|
688
703
|
if (this.callbacks.addable && e.ctrlKey) {
|
|
689
704
|
addable.click()
|
|
690
705
|
} else {
|
|
@@ -897,7 +912,6 @@ export default class Render {
|
|
|
897
912
|
public listDiv(): HTMLDivElement {
|
|
898
913
|
const options = document.createElement('div')
|
|
899
914
|
options.classList.add(this.classes.list)
|
|
900
|
-
options.setAttribute('role', 'listbox')
|
|
901
915
|
|
|
902
916
|
return options
|
|
903
917
|
}
|
|
@@ -1117,6 +1131,7 @@ export default class Render {
|
|
|
1117
1131
|
// Create option
|
|
1118
1132
|
const optionEl = document.createElement('div')
|
|
1119
1133
|
optionEl.dataset.id = option.id // Dataset id for identifying an option
|
|
1134
|
+
optionEl.id = option.id
|
|
1120
1135
|
optionEl.classList.add(this.classes.option)
|
|
1121
1136
|
optionEl.setAttribute('role', 'option') // WCAG attribute
|
|
1122
1137
|
if (option.class) {
|
|
@@ -1164,8 +1179,11 @@ export default class Render {
|
|
|
1164
1179
|
// If option is selected
|
|
1165
1180
|
if (option.selected) {
|
|
1166
1181
|
optionEl.classList.add(this.classes.selected)
|
|
1182
|
+
optionEl.setAttribute('aria-selected', 'true')
|
|
1183
|
+
this.main.main.setAttribute('aria-activedescendant', optionEl.id)
|
|
1167
1184
|
} else {
|
|
1168
1185
|
optionEl.classList.remove(this.classes.selected)
|
|
1186
|
+
optionEl.setAttribute('aria-selected', 'false')
|
|
1169
1187
|
}
|
|
1170
1188
|
|
|
1171
1189
|
// Add click event listener
|
|
@@ -10,6 +10,7 @@ export default class Settings {
|
|
|
10
10
|
// Dynamic settings
|
|
11
11
|
public isMultiple: boolean = false
|
|
12
12
|
public isOpen: boolean = false
|
|
13
|
+
public isWindowFocused: boolean = true
|
|
13
14
|
public triggerFocus: boolean = true
|
|
14
15
|
public intervalMove: NodeJS.Timeout | null = null
|
|
15
16
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare function generateID(): string;
|
|
2
2
|
export declare function hasClassInTree(element: HTMLElement, className: string): any;
|
|
3
|
-
export declare function debounce
|
|
3
|
+
export declare function debounce<T extends (...args: any[]) => void>(func: T, wait?: number, immediate?: boolean): () => void;
|
|
4
4
|
export declare function isEqual(a: any, b: any): boolean;
|
|
5
5
|
export declare function kebabCase(str: string): string;
|
|
@@ -36,10 +36,11 @@ export default class SlimSelect {
|
|
|
36
36
|
setSelected(value: string | string[], runAfterChange?: boolean): void;
|
|
37
37
|
addOption(option: OptionOptional): void;
|
|
38
38
|
open(): void;
|
|
39
|
-
close(): void;
|
|
39
|
+
close(eventType?: string | null): void;
|
|
40
40
|
search(value: string): void;
|
|
41
41
|
destroy(): void;
|
|
42
42
|
private windowResize;
|
|
43
43
|
private windowScroll;
|
|
44
44
|
private documentClick;
|
|
45
|
+
private windowVisibilityChange;
|
|
45
46
|
}
|
|
@@ -91,8 +91,9 @@ export default class Render {
|
|
|
91
91
|
open(): void;
|
|
92
92
|
close(): void;
|
|
93
93
|
updateClassStyles(): void;
|
|
94
|
+
updateAriaAttributes(): void;
|
|
94
95
|
mainDiv(): Main;
|
|
95
|
-
mainFocus(trigger: boolean): void;
|
|
96
|
+
mainFocus(trigger: boolean, eventType: string | null): void;
|
|
96
97
|
placeholder(): HTMLDivElement;
|
|
97
98
|
renderValues(): void;
|
|
98
99
|
private renderSingleValue;
|
|
@@ -59,6 +59,7 @@ class Settings {
|
|
|
59
59
|
this.class = [];
|
|
60
60
|
this.isMultiple = false;
|
|
61
61
|
this.isOpen = false;
|
|
62
|
+
this.isWindowFocused = true;
|
|
62
63
|
this.triggerFocus = true;
|
|
63
64
|
this.intervalMove = null;
|
|
64
65
|
if (!settings) {
|
|
@@ -346,6 +347,7 @@ class Render {
|
|
|
346
347
|
this.main = this.mainDiv();
|
|
347
348
|
this.content = this.contentDiv();
|
|
348
349
|
this.updateClassStyles();
|
|
350
|
+
this.updateAriaAttributes();
|
|
349
351
|
this.settings.contentLocation.appendChild(this.content.main);
|
|
350
352
|
}
|
|
351
353
|
enable() {
|
|
@@ -359,6 +361,7 @@ class Render {
|
|
|
359
361
|
open() {
|
|
360
362
|
this.main.arrow.path.setAttribute('d', this.classes.arrowOpen);
|
|
361
363
|
this.main.main.classList.add(this.settings.openPosition === 'up' ? this.classes.openAbove : this.classes.openBelow);
|
|
364
|
+
this.main.main.setAttribute('aria-expanded', 'true');
|
|
362
365
|
this.moveContent();
|
|
363
366
|
const selectedOptions = this.store.getSelectedOptions();
|
|
364
367
|
if (selectedOptions.length) {
|
|
@@ -372,6 +375,7 @@ class Render {
|
|
|
372
375
|
close() {
|
|
373
376
|
this.main.main.classList.remove(this.classes.openAbove);
|
|
374
377
|
this.main.main.classList.remove(this.classes.openBelow);
|
|
378
|
+
this.main.main.setAttribute('aria-expanded', 'false');
|
|
375
379
|
this.content.main.classList.remove(this.classes.openAbove);
|
|
376
380
|
this.content.main.classList.remove(this.classes.openBelow);
|
|
377
381
|
this.main.arrow.path.setAttribute('d', this.classes.arrowClose);
|
|
@@ -398,15 +402,18 @@ class Render {
|
|
|
398
402
|
this.content.main.classList.add('ss-' + this.settings.contentPosition);
|
|
399
403
|
}
|
|
400
404
|
}
|
|
405
|
+
updateAriaAttributes() {
|
|
406
|
+
this.main.main.role = 'combobox';
|
|
407
|
+
this.main.main.setAttribute('aria-haspopup', 'listbox');
|
|
408
|
+
this.main.main.setAttribute('aria-controls', this.content.main.id);
|
|
409
|
+
this.main.main.setAttribute('aria-expanded', 'false');
|
|
410
|
+
this.content.main.setAttribute('role', 'listbox');
|
|
411
|
+
}
|
|
401
412
|
mainDiv() {
|
|
402
413
|
const main = document.createElement('div');
|
|
403
414
|
main.dataset.id = this.settings.id;
|
|
415
|
+
main.id = this.settings.id;
|
|
404
416
|
main.tabIndex = 0;
|
|
405
|
-
main.onfocus = () => {
|
|
406
|
-
if (this.settings.triggerFocus) {
|
|
407
|
-
this.callbacks.open();
|
|
408
|
-
}
|
|
409
|
-
};
|
|
410
417
|
main.onkeydown = (e) => {
|
|
411
418
|
switch (e.key) {
|
|
412
419
|
case 'ArrowUp':
|
|
@@ -418,6 +425,8 @@ class Render {
|
|
|
418
425
|
this.callbacks.close();
|
|
419
426
|
return true;
|
|
420
427
|
case 'Enter':
|
|
428
|
+
case ' ':
|
|
429
|
+
this.callbacks.open();
|
|
421
430
|
const highlighted = this.content.list.querySelector('.' + this.classes.highlighted);
|
|
422
431
|
if (highlighted) {
|
|
423
432
|
highlighted.click();
|
|
@@ -494,11 +503,13 @@ class Render {
|
|
|
494
503
|
},
|
|
495
504
|
};
|
|
496
505
|
}
|
|
497
|
-
mainFocus(trigger) {
|
|
506
|
+
mainFocus(trigger, eventType) {
|
|
498
507
|
if (!trigger) {
|
|
499
508
|
this.settings.triggerFocus = false;
|
|
500
509
|
}
|
|
501
|
-
|
|
510
|
+
if (eventType !== 'click') {
|
|
511
|
+
this.main.main.focus({ preventScroll: true });
|
|
512
|
+
}
|
|
502
513
|
this.settings.triggerFocus = true;
|
|
503
514
|
}
|
|
504
515
|
placeholder() {
|
|
@@ -675,6 +686,7 @@ class Render {
|
|
|
675
686
|
contentDiv() {
|
|
676
687
|
const main = document.createElement('div');
|
|
677
688
|
main.dataset.id = this.settings.id;
|
|
689
|
+
main.id = this.settings.id;
|
|
678
690
|
const search = this.searchDiv();
|
|
679
691
|
main.appendChild(search.main);
|
|
680
692
|
const list = this.listDiv();
|
|
@@ -742,6 +754,7 @@ class Render {
|
|
|
742
754
|
this.callbacks.close();
|
|
743
755
|
return false;
|
|
744
756
|
case 'Enter':
|
|
757
|
+
case ' ':
|
|
745
758
|
if (this.callbacks.addable && e.ctrlKey) {
|
|
746
759
|
addable.click();
|
|
747
760
|
}
|
|
@@ -893,7 +906,6 @@ class Render {
|
|
|
893
906
|
listDiv() {
|
|
894
907
|
const options = document.createElement('div');
|
|
895
908
|
options.classList.add(this.classes.list);
|
|
896
|
-
options.setAttribute('role', 'listbox');
|
|
897
909
|
return options;
|
|
898
910
|
}
|
|
899
911
|
renderError(error) {
|
|
@@ -1038,6 +1050,7 @@ class Render {
|
|
|
1038
1050
|
}
|
|
1039
1051
|
const optionEl = document.createElement('div');
|
|
1040
1052
|
optionEl.dataset.id = option.id;
|
|
1053
|
+
optionEl.id = option.id;
|
|
1041
1054
|
optionEl.classList.add(this.classes.option);
|
|
1042
1055
|
optionEl.setAttribute('role', 'option');
|
|
1043
1056
|
if (option.class) {
|
|
@@ -1071,9 +1084,12 @@ class Render {
|
|
|
1071
1084
|
}
|
|
1072
1085
|
if (option.selected) {
|
|
1073
1086
|
optionEl.classList.add(this.classes.selected);
|
|
1087
|
+
optionEl.setAttribute('aria-selected', 'true');
|
|
1088
|
+
this.main.main.setAttribute('aria-activedescendant', optionEl.id);
|
|
1074
1089
|
}
|
|
1075
1090
|
else {
|
|
1076
1091
|
optionEl.classList.remove(this.classes.selected);
|
|
1092
|
+
optionEl.setAttribute('aria-selected', 'false');
|
|
1077
1093
|
}
|
|
1078
1094
|
optionEl.addEventListener('click', (e) => {
|
|
1079
1095
|
e.preventDefault();
|
|
@@ -1507,8 +1523,19 @@ class SlimSelect {
|
|
|
1507
1523
|
return;
|
|
1508
1524
|
}
|
|
1509
1525
|
if (e.target && !hasClassInTree(e.target, this.settings.id)) {
|
|
1526
|
+
this.close(e.type);
|
|
1527
|
+
}
|
|
1528
|
+
};
|
|
1529
|
+
this.windowVisibilityChange = () => {
|
|
1530
|
+
if (document.hidden) {
|
|
1531
|
+
this.settings.isWindowFocused = false;
|
|
1510
1532
|
this.close();
|
|
1511
1533
|
}
|
|
1534
|
+
else {
|
|
1535
|
+
setTimeout(() => {
|
|
1536
|
+
this.settings.isWindowFocused = true;
|
|
1537
|
+
}, 20);
|
|
1538
|
+
}
|
|
1512
1539
|
};
|
|
1513
1540
|
this.selectEl = (typeof config.select === 'string' ? document.querySelector(config.select) : config.select);
|
|
1514
1541
|
if (!this.selectEl) {
|
|
@@ -1581,6 +1608,14 @@ class SlimSelect {
|
|
|
1581
1608
|
this.render = new Render(this.settings, this.store, callbacks);
|
|
1582
1609
|
this.render.renderValues();
|
|
1583
1610
|
this.render.renderOptions(this.store.getData());
|
|
1611
|
+
const selectAriaLabel = this.selectEl.getAttribute('aria-label');
|
|
1612
|
+
const selectAriaLabelledBy = this.selectEl.getAttribute('aria-labelledby');
|
|
1613
|
+
if (selectAriaLabel) {
|
|
1614
|
+
this.render.main.main.setAttribute('aria-label', selectAriaLabel);
|
|
1615
|
+
}
|
|
1616
|
+
else if (selectAriaLabelledBy) {
|
|
1617
|
+
this.render.main.main.setAttribute('aria-labelledby', selectAriaLabelledBy);
|
|
1618
|
+
}
|
|
1584
1619
|
if (this.selectEl.parentNode) {
|
|
1585
1620
|
this.selectEl.parentNode.insertBefore(this.render.main.main, this.selectEl.nextSibling);
|
|
1586
1621
|
}
|
|
@@ -1589,6 +1624,7 @@ class SlimSelect {
|
|
|
1589
1624
|
if (this.settings.openPosition === 'auto') {
|
|
1590
1625
|
window.addEventListener('scroll', this.windowScroll, false);
|
|
1591
1626
|
}
|
|
1627
|
+
document.addEventListener('visibilitychange', this.windowVisibilityChange);
|
|
1592
1628
|
if (this.settings.disabled) {
|
|
1593
1629
|
this.disable();
|
|
1594
1630
|
}
|
|
@@ -1649,7 +1685,9 @@ class SlimSelect {
|
|
|
1649
1685
|
}
|
|
1650
1686
|
addOption(option) {
|
|
1651
1687
|
const selected = this.store.getSelected();
|
|
1652
|
-
this.store.
|
|
1688
|
+
if (!this.store.getDataOptions().some((o) => { var _a; return o.value === ((_a = option.value) !== null && _a !== void 0 ? _a : option.text); })) {
|
|
1689
|
+
this.store.addOption(option);
|
|
1690
|
+
}
|
|
1653
1691
|
const data = this.store.getData();
|
|
1654
1692
|
this.select.updateOptions(data);
|
|
1655
1693
|
this.render.renderValues();
|
|
@@ -1682,7 +1720,7 @@ class SlimSelect {
|
|
|
1682
1720
|
this.settings.intervalMove = setInterval(this.render.moveContent.bind(this.render), 500);
|
|
1683
1721
|
}
|
|
1684
1722
|
}
|
|
1685
|
-
close() {
|
|
1723
|
+
close(eventType = null) {
|
|
1686
1724
|
if (!this.settings.isOpen || this.settings.alwaysOpen) {
|
|
1687
1725
|
return;
|
|
1688
1726
|
}
|
|
@@ -1693,7 +1731,7 @@ class SlimSelect {
|
|
|
1693
1731
|
if (this.render.content.search.input.value !== '') {
|
|
1694
1732
|
this.search('');
|
|
1695
1733
|
}
|
|
1696
|
-
this.render.mainFocus(false);
|
|
1734
|
+
this.render.mainFocus(false, eventType);
|
|
1697
1735
|
setTimeout(() => {
|
|
1698
1736
|
if (this.events.afterClose) {
|
|
1699
1737
|
this.events.afterClose();
|
|
@@ -1737,6 +1775,7 @@ class SlimSelect {
|
|
|
1737
1775
|
if (this.settings.openPosition === 'auto') {
|
|
1738
1776
|
window.removeEventListener('scroll', this.windowScroll, false);
|
|
1739
1777
|
}
|
|
1778
|
+
document.removeEventListener('visibilitychange', this.windowVisibilityChange);
|
|
1740
1779
|
this.store.setData([]);
|
|
1741
1780
|
this.render.destroy();
|
|
1742
1781
|
this.select.destroy();
|
|
@@ -60,6 +60,7 @@ var SlimSelectVue = (function (vue) {
|
|
|
60
60
|
this.class = [];
|
|
61
61
|
this.isMultiple = false;
|
|
62
62
|
this.isOpen = false;
|
|
63
|
+
this.isWindowFocused = true;
|
|
63
64
|
this.triggerFocus = true;
|
|
64
65
|
this.intervalMove = null;
|
|
65
66
|
if (!settings) {
|
|
@@ -347,6 +348,7 @@ var SlimSelectVue = (function (vue) {
|
|
|
347
348
|
this.main = this.mainDiv();
|
|
348
349
|
this.content = this.contentDiv();
|
|
349
350
|
this.updateClassStyles();
|
|
351
|
+
this.updateAriaAttributes();
|
|
350
352
|
this.settings.contentLocation.appendChild(this.content.main);
|
|
351
353
|
}
|
|
352
354
|
enable() {
|
|
@@ -360,6 +362,7 @@ var SlimSelectVue = (function (vue) {
|
|
|
360
362
|
open() {
|
|
361
363
|
this.main.arrow.path.setAttribute('d', this.classes.arrowOpen);
|
|
362
364
|
this.main.main.classList.add(this.settings.openPosition === 'up' ? this.classes.openAbove : this.classes.openBelow);
|
|
365
|
+
this.main.main.setAttribute('aria-expanded', 'true');
|
|
363
366
|
this.moveContent();
|
|
364
367
|
const selectedOptions = this.store.getSelectedOptions();
|
|
365
368
|
if (selectedOptions.length) {
|
|
@@ -373,6 +376,7 @@ var SlimSelectVue = (function (vue) {
|
|
|
373
376
|
close() {
|
|
374
377
|
this.main.main.classList.remove(this.classes.openAbove);
|
|
375
378
|
this.main.main.classList.remove(this.classes.openBelow);
|
|
379
|
+
this.main.main.setAttribute('aria-expanded', 'false');
|
|
376
380
|
this.content.main.classList.remove(this.classes.openAbove);
|
|
377
381
|
this.content.main.classList.remove(this.classes.openBelow);
|
|
378
382
|
this.main.arrow.path.setAttribute('d', this.classes.arrowClose);
|
|
@@ -399,15 +403,18 @@ var SlimSelectVue = (function (vue) {
|
|
|
399
403
|
this.content.main.classList.add('ss-' + this.settings.contentPosition);
|
|
400
404
|
}
|
|
401
405
|
}
|
|
406
|
+
updateAriaAttributes() {
|
|
407
|
+
this.main.main.role = 'combobox';
|
|
408
|
+
this.main.main.setAttribute('aria-haspopup', 'listbox');
|
|
409
|
+
this.main.main.setAttribute('aria-controls', this.content.main.id);
|
|
410
|
+
this.main.main.setAttribute('aria-expanded', 'false');
|
|
411
|
+
this.content.main.setAttribute('role', 'listbox');
|
|
412
|
+
}
|
|
402
413
|
mainDiv() {
|
|
403
414
|
const main = document.createElement('div');
|
|
404
415
|
main.dataset.id = this.settings.id;
|
|
416
|
+
main.id = this.settings.id;
|
|
405
417
|
main.tabIndex = 0;
|
|
406
|
-
main.onfocus = () => {
|
|
407
|
-
if (this.settings.triggerFocus) {
|
|
408
|
-
this.callbacks.open();
|
|
409
|
-
}
|
|
410
|
-
};
|
|
411
418
|
main.onkeydown = (e) => {
|
|
412
419
|
switch (e.key) {
|
|
413
420
|
case 'ArrowUp':
|
|
@@ -419,6 +426,8 @@ var SlimSelectVue = (function (vue) {
|
|
|
419
426
|
this.callbacks.close();
|
|
420
427
|
return true;
|
|
421
428
|
case 'Enter':
|
|
429
|
+
case ' ':
|
|
430
|
+
this.callbacks.open();
|
|
422
431
|
const highlighted = this.content.list.querySelector('.' + this.classes.highlighted);
|
|
423
432
|
if (highlighted) {
|
|
424
433
|
highlighted.click();
|
|
@@ -495,11 +504,13 @@ var SlimSelectVue = (function (vue) {
|
|
|
495
504
|
},
|
|
496
505
|
};
|
|
497
506
|
}
|
|
498
|
-
mainFocus(trigger) {
|
|
507
|
+
mainFocus(trigger, eventType) {
|
|
499
508
|
if (!trigger) {
|
|
500
509
|
this.settings.triggerFocus = false;
|
|
501
510
|
}
|
|
502
|
-
|
|
511
|
+
if (eventType !== 'click') {
|
|
512
|
+
this.main.main.focus({ preventScroll: true });
|
|
513
|
+
}
|
|
503
514
|
this.settings.triggerFocus = true;
|
|
504
515
|
}
|
|
505
516
|
placeholder() {
|
|
@@ -676,6 +687,7 @@ var SlimSelectVue = (function (vue) {
|
|
|
676
687
|
contentDiv() {
|
|
677
688
|
const main = document.createElement('div');
|
|
678
689
|
main.dataset.id = this.settings.id;
|
|
690
|
+
main.id = this.settings.id;
|
|
679
691
|
const search = this.searchDiv();
|
|
680
692
|
main.appendChild(search.main);
|
|
681
693
|
const list = this.listDiv();
|
|
@@ -743,6 +755,7 @@ var SlimSelectVue = (function (vue) {
|
|
|
743
755
|
this.callbacks.close();
|
|
744
756
|
return false;
|
|
745
757
|
case 'Enter':
|
|
758
|
+
case ' ':
|
|
746
759
|
if (this.callbacks.addable && e.ctrlKey) {
|
|
747
760
|
addable.click();
|
|
748
761
|
}
|
|
@@ -894,7 +907,6 @@ var SlimSelectVue = (function (vue) {
|
|
|
894
907
|
listDiv() {
|
|
895
908
|
const options = document.createElement('div');
|
|
896
909
|
options.classList.add(this.classes.list);
|
|
897
|
-
options.setAttribute('role', 'listbox');
|
|
898
910
|
return options;
|
|
899
911
|
}
|
|
900
912
|
renderError(error) {
|
|
@@ -1039,6 +1051,7 @@ var SlimSelectVue = (function (vue) {
|
|
|
1039
1051
|
}
|
|
1040
1052
|
const optionEl = document.createElement('div');
|
|
1041
1053
|
optionEl.dataset.id = option.id;
|
|
1054
|
+
optionEl.id = option.id;
|
|
1042
1055
|
optionEl.classList.add(this.classes.option);
|
|
1043
1056
|
optionEl.setAttribute('role', 'option');
|
|
1044
1057
|
if (option.class) {
|
|
@@ -1072,9 +1085,12 @@ var SlimSelectVue = (function (vue) {
|
|
|
1072
1085
|
}
|
|
1073
1086
|
if (option.selected) {
|
|
1074
1087
|
optionEl.classList.add(this.classes.selected);
|
|
1088
|
+
optionEl.setAttribute('aria-selected', 'true');
|
|
1089
|
+
this.main.main.setAttribute('aria-activedescendant', optionEl.id);
|
|
1075
1090
|
}
|
|
1076
1091
|
else {
|
|
1077
1092
|
optionEl.classList.remove(this.classes.selected);
|
|
1093
|
+
optionEl.setAttribute('aria-selected', 'false');
|
|
1078
1094
|
}
|
|
1079
1095
|
optionEl.addEventListener('click', (e) => {
|
|
1080
1096
|
e.preventDefault();
|
|
@@ -1508,8 +1524,19 @@ var SlimSelectVue = (function (vue) {
|
|
|
1508
1524
|
return;
|
|
1509
1525
|
}
|
|
1510
1526
|
if (e.target && !hasClassInTree(e.target, this.settings.id)) {
|
|
1527
|
+
this.close(e.type);
|
|
1528
|
+
}
|
|
1529
|
+
};
|
|
1530
|
+
this.windowVisibilityChange = () => {
|
|
1531
|
+
if (document.hidden) {
|
|
1532
|
+
this.settings.isWindowFocused = false;
|
|
1511
1533
|
this.close();
|
|
1512
1534
|
}
|
|
1535
|
+
else {
|
|
1536
|
+
setTimeout(() => {
|
|
1537
|
+
this.settings.isWindowFocused = true;
|
|
1538
|
+
}, 20);
|
|
1539
|
+
}
|
|
1513
1540
|
};
|
|
1514
1541
|
this.selectEl = (typeof config.select === 'string' ? document.querySelector(config.select) : config.select);
|
|
1515
1542
|
if (!this.selectEl) {
|
|
@@ -1582,6 +1609,14 @@ var SlimSelectVue = (function (vue) {
|
|
|
1582
1609
|
this.render = new Render(this.settings, this.store, callbacks);
|
|
1583
1610
|
this.render.renderValues();
|
|
1584
1611
|
this.render.renderOptions(this.store.getData());
|
|
1612
|
+
const selectAriaLabel = this.selectEl.getAttribute('aria-label');
|
|
1613
|
+
const selectAriaLabelledBy = this.selectEl.getAttribute('aria-labelledby');
|
|
1614
|
+
if (selectAriaLabel) {
|
|
1615
|
+
this.render.main.main.setAttribute('aria-label', selectAriaLabel);
|
|
1616
|
+
}
|
|
1617
|
+
else if (selectAriaLabelledBy) {
|
|
1618
|
+
this.render.main.main.setAttribute('aria-labelledby', selectAriaLabelledBy);
|
|
1619
|
+
}
|
|
1585
1620
|
if (this.selectEl.parentNode) {
|
|
1586
1621
|
this.selectEl.parentNode.insertBefore(this.render.main.main, this.selectEl.nextSibling);
|
|
1587
1622
|
}
|
|
@@ -1590,6 +1625,7 @@ var SlimSelectVue = (function (vue) {
|
|
|
1590
1625
|
if (this.settings.openPosition === 'auto') {
|
|
1591
1626
|
window.addEventListener('scroll', this.windowScroll, false);
|
|
1592
1627
|
}
|
|
1628
|
+
document.addEventListener('visibilitychange', this.windowVisibilityChange);
|
|
1593
1629
|
if (this.settings.disabled) {
|
|
1594
1630
|
this.disable();
|
|
1595
1631
|
}
|
|
@@ -1650,7 +1686,9 @@ var SlimSelectVue = (function (vue) {
|
|
|
1650
1686
|
}
|
|
1651
1687
|
addOption(option) {
|
|
1652
1688
|
const selected = this.store.getSelected();
|
|
1653
|
-
this.store.
|
|
1689
|
+
if (!this.store.getDataOptions().some((o) => { var _a; return o.value === ((_a = option.value) !== null && _a !== void 0 ? _a : option.text); })) {
|
|
1690
|
+
this.store.addOption(option);
|
|
1691
|
+
}
|
|
1654
1692
|
const data = this.store.getData();
|
|
1655
1693
|
this.select.updateOptions(data);
|
|
1656
1694
|
this.render.renderValues();
|
|
@@ -1683,7 +1721,7 @@ var SlimSelectVue = (function (vue) {
|
|
|
1683
1721
|
this.settings.intervalMove = setInterval(this.render.moveContent.bind(this.render), 500);
|
|
1684
1722
|
}
|
|
1685
1723
|
}
|
|
1686
|
-
close() {
|
|
1724
|
+
close(eventType = null) {
|
|
1687
1725
|
if (!this.settings.isOpen || this.settings.alwaysOpen) {
|
|
1688
1726
|
return;
|
|
1689
1727
|
}
|
|
@@ -1694,7 +1732,7 @@ var SlimSelectVue = (function (vue) {
|
|
|
1694
1732
|
if (this.render.content.search.input.value !== '') {
|
|
1695
1733
|
this.search('');
|
|
1696
1734
|
}
|
|
1697
|
-
this.render.mainFocus(false);
|
|
1735
|
+
this.render.mainFocus(false, eventType);
|
|
1698
1736
|
setTimeout(() => {
|
|
1699
1737
|
if (this.events.afterClose) {
|
|
1700
1738
|
this.events.afterClose();
|
|
@@ -1738,6 +1776,7 @@ var SlimSelectVue = (function (vue) {
|
|
|
1738
1776
|
if (this.settings.openPosition === 'auto') {
|
|
1739
1777
|
window.removeEventListener('scroll', this.windowScroll, false);
|
|
1740
1778
|
}
|
|
1779
|
+
document.removeEventListener('visibilitychange', this.windowVisibilityChange);
|
|
1741
1780
|
this.store.setData([]);
|
|
1742
1781
|
this.render.destroy();
|
|
1743
1782
|
this.select.destroy();
|