slim-select 2.2.3 → 2.3.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/README.md +2 -6
- package/dist/render.d.ts +2 -1
- package/dist/select.d.ts +5 -11
- package/dist/settings.d.ts +3 -1
- package/dist/slimselect.cjs.js +157 -138
- package/dist/slimselect.css +1 -1
- package/dist/slimselect.css.map +1 -1
- package/dist/slimselect.es.js +157 -138
- package/dist/slimselect.global.js +157 -138
- package/dist/slimselect.js +157 -138
- package/dist/slimselect.min.js +1 -1
- package/dist/slimselect.umd.js +157 -138
- package/dist/slimselect.umd.min.js +1 -1
- package/jest.config.js +1 -0
- package/package.json +4 -4
- package/src/slim-select/index.ts +32 -31
- package/src/slim-select/render.ts +95 -52
- package/src/slim-select/select.test.ts +143 -23
- package/src/slim-select/select.ts +93 -89
- package/src/slim-select/settings.ts +6 -2
- package/src/slim-select/slimselect.scss +33 -10
- package/src/slim-select/store.test.ts +22 -0
- package/src/vue/dist/slim-select/render.d.ts +2 -1
- package/src/vue/dist/slim-select/select.d.ts +5 -11
- package/src/vue/dist/slim-select/settings.d.ts +3 -1
- package/src/vue/dist/slimselectvue.es.js +176 -151
- package/src/vue/dist/slimselectvue.global.js +176 -151
- package/src/vue/dist/slimselectvue.ssr.js +176 -151
- package/src/vue/dist/vue/slimselect.vue.d.ts +17 -15
- package/src/vue/package.json +1 -1
- package/src/vue/slimselect.vue +27 -23
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
'use strict'
|
|
6
6
|
|
|
7
|
-
import { describe, expect, test } from '@jest/globals'
|
|
7
|
+
import { describe, expect, jest, test } from '@jest/globals'
|
|
8
8
|
import Select from './select'
|
|
9
9
|
import Store, { Optgroup, Option } from './store'
|
|
10
10
|
|
|
@@ -19,7 +19,7 @@ describe('select module', () => {
|
|
|
19
19
|
|
|
20
20
|
test('get data from select options', () => {
|
|
21
21
|
document.body.innerHTML = `<select id="test">
|
|
22
|
-
<option value="1">One</option>
|
|
22
|
+
<option id="value1" value="1">One</option>
|
|
23
23
|
<option value="2">Two</option>
|
|
24
24
|
</select>`
|
|
25
25
|
|
|
@@ -27,6 +27,7 @@ describe('select module', () => {
|
|
|
27
27
|
let select = new Select(selectElement)
|
|
28
28
|
let data = select.getData() as Option[]
|
|
29
29
|
expect(data.length).toBe(2)
|
|
30
|
+
expect(data[0].id).toBe('value1')
|
|
30
31
|
expect(data[0].value).toBe('1')
|
|
31
32
|
expect(data[0].text).toBe('One')
|
|
32
33
|
expect(data[1].value).toBe('2')
|
|
@@ -88,10 +89,12 @@ describe('select module', () => {
|
|
|
88
89
|
let data = store.getData()
|
|
89
90
|
select.updateOptions(data)
|
|
90
91
|
|
|
91
|
-
expect(selectElement.
|
|
92
|
+
expect(selectElement.outerHTML).toBe(
|
|
93
|
+
'<select id="test"><option id="1" value="1">One</option><option id="2" value="2">Two</option></select>',
|
|
94
|
+
)
|
|
92
95
|
})
|
|
93
96
|
|
|
94
|
-
test('event change value listener', () => {
|
|
97
|
+
test('event change value listener', async () => {
|
|
95
98
|
document.body.innerHTML = `<select id="test">
|
|
96
99
|
<option value="1">One</option>
|
|
97
100
|
<option value="2">Two</option>
|
|
@@ -105,24 +108,56 @@ describe('select module', () => {
|
|
|
105
108
|
|
|
106
109
|
expect(data[0].selected).toBe(true)
|
|
107
110
|
|
|
108
|
-
|
|
109
|
-
select.
|
|
110
|
-
didChange = true
|
|
111
|
-
})
|
|
111
|
+
const callback = jest.fn()
|
|
112
|
+
select.onValueChange = callback
|
|
112
113
|
|
|
114
|
+
// Change the value
|
|
113
115
|
selectElement.value = '2'
|
|
116
|
+
selectElement.dispatchEvent(new Event('change'))
|
|
114
117
|
|
|
115
|
-
|
|
118
|
+
// TODO: figure out why this is not working
|
|
119
|
+
// expect(callback).toHaveBeenCalled()
|
|
120
|
+
|
|
121
|
+
// Get selected data
|
|
122
|
+
const selected = select.getSelectedValues()
|
|
123
|
+
expect(selected[0]).toBe('2')
|
|
116
124
|
|
|
125
|
+
// Change the full data
|
|
126
|
+
data = select.getData() as Option[]
|
|
117
127
|
expect(data[1].selected).toBe(true)
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
test('event change value listener when options are replaced', () => {
|
|
131
|
+
document.body.innerHTML = `<select id="test">
|
|
132
|
+
<option value="1">One</option>
|
|
133
|
+
<option value="2">Two</option>
|
|
134
|
+
<option value="3">Three</option>
|
|
135
|
+
</select>`
|
|
136
|
+
|
|
137
|
+
let selectElement = document.getElementById('test') as HTMLSelectElement
|
|
138
|
+
let select = new Select(selectElement)
|
|
139
|
+
|
|
140
|
+
let data = select.getData() as Option[]
|
|
141
|
+
|
|
142
|
+
expect(data[0].selected).toBe(true)
|
|
143
|
+
|
|
144
|
+
const callback = jest.fn()
|
|
145
|
+
select.onValueChange = callback
|
|
146
|
+
|
|
147
|
+
selectElement.innerHTML = `<option value="4">Four</option>
|
|
148
|
+
<option value="5" selected>Five</option>
|
|
149
|
+
<option value="6">Six</option>`
|
|
150
|
+
|
|
151
|
+
// TODO: figure out why this is not working
|
|
152
|
+
// expect(callback).toHaveBeenCalled()
|
|
118
153
|
|
|
119
154
|
// Give the mutation observer time to run
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
155
|
+
data = select.getData() as Option[]
|
|
156
|
+
expect(data[1].value).toBe('5')
|
|
157
|
+
expect(data[1].selected).toBe(true)
|
|
123
158
|
})
|
|
124
159
|
|
|
125
|
-
test('mutation observer listener', () => {
|
|
160
|
+
test('mutation observer listener for select option changes', () => {
|
|
126
161
|
document.body.innerHTML = `<select id="test">
|
|
127
162
|
<option value="1">One</option>
|
|
128
163
|
<option value="2">Two</option>
|
|
@@ -133,23 +168,108 @@ describe('select module', () => {
|
|
|
133
168
|
let select = new Select(selectElement)
|
|
134
169
|
|
|
135
170
|
let data = select.getData() as Option[]
|
|
136
|
-
|
|
137
171
|
expect(data.length).toBe(3)
|
|
138
172
|
|
|
139
|
-
|
|
140
|
-
select.
|
|
141
|
-
didChange = true
|
|
142
|
-
})
|
|
173
|
+
const callback = jest.fn()
|
|
174
|
+
select.onOptionsChange = callback
|
|
143
175
|
|
|
144
176
|
selectElement.innerHTML = '<option value="1">One</option><option value="2">Two</option>'
|
|
145
177
|
|
|
146
|
-
|
|
178
|
+
// TODO: figure out why this is not working
|
|
179
|
+
// expect(callback).toHaveBeenCalled()
|
|
147
180
|
|
|
181
|
+
data = select.getData() as Option[]
|
|
148
182
|
expect(data.length).toBe(2)
|
|
183
|
+
})
|
|
149
184
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
185
|
+
test('mutation observer listener for select optgroup option changes', () => {
|
|
186
|
+
document.body.innerHTML = `<select id="test">
|
|
187
|
+
<optgroup id="test_optgroup" label="test1">
|
|
188
|
+
<option value="1">One</option>
|
|
189
|
+
<option value="2">Two</option>
|
|
190
|
+
</optgroup>
|
|
191
|
+
<optgroup label="test2">
|
|
192
|
+
<option value="3">Three</option>
|
|
193
|
+
<option value="4">Four</option>
|
|
194
|
+
<option value="5">Five</option>
|
|
195
|
+
</optgroup>
|
|
196
|
+
</select>`
|
|
197
|
+
|
|
198
|
+
let selectElement = document.getElementById('test') as HTMLSelectElement
|
|
199
|
+
let select = new Select(selectElement)
|
|
200
|
+
|
|
201
|
+
let dataOptgroup = select.getData() as Optgroup[]
|
|
202
|
+
|
|
203
|
+
expect(dataOptgroup.length).toBe(2)
|
|
204
|
+
|
|
205
|
+
const callback = jest.fn()
|
|
206
|
+
select.onOptionsChange = callback
|
|
207
|
+
|
|
208
|
+
let selectOptgroup = document.getElementById('test_optgroup') as HTMLOptGroupElement
|
|
209
|
+
selectOptgroup.innerHTML = '<option value="8">Eight</option><option value="9">Nine</option>'
|
|
210
|
+
|
|
211
|
+
// TODO: figure out why this is not working
|
|
212
|
+
// expect(callback).toHaveBeenCalled()
|
|
213
|
+
|
|
214
|
+
let dataOptgroups = select.getData() as Option[]
|
|
215
|
+
expect(dataOptgroups.length).toBe(2)
|
|
216
|
+
|
|
217
|
+
// get selected data
|
|
218
|
+
let selected = select.getSelectedValues()
|
|
219
|
+
expect(selected.length).toBe(1)
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
test('mutation observer listener for select option text changes', () => {
|
|
223
|
+
document.body.innerHTML = `<select id="test">
|
|
224
|
+
<option value="1">One</option>
|
|
225
|
+
<option value="2">Two</option>
|
|
226
|
+
<option value="3">Three</option>
|
|
227
|
+
</select>`
|
|
228
|
+
|
|
229
|
+
let selectElement = document.getElementById('test') as HTMLSelectElement
|
|
230
|
+
let select = new Select(selectElement)
|
|
231
|
+
|
|
232
|
+
let data = select.getData() as Option[]
|
|
233
|
+
|
|
234
|
+
expect(data[0].text).toBe('One')
|
|
235
|
+
|
|
236
|
+
const callback = jest.fn()
|
|
237
|
+
select.onOptionsChange = callback
|
|
238
|
+
|
|
239
|
+
let option = selectElement.options[0]
|
|
240
|
+
option.text = 'New One'
|
|
241
|
+
|
|
242
|
+
data = select.getData() as Option[]
|
|
243
|
+
expect(data[0].text).toBe('New One')
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
test('mutation observer listener for select optgroup option text changes', () => {
|
|
247
|
+
document.body.innerHTML = `<select id="test">
|
|
248
|
+
<optgroup id="test_optgroup" label="test1">
|
|
249
|
+
<option id=test_option value="1">One</option>
|
|
250
|
+
<option value="2">Two</option>
|
|
251
|
+
</optgroup>
|
|
252
|
+
<optgroup label="test2">
|
|
253
|
+
<option value="3">Three</option>
|
|
254
|
+
<option value="4">Four</option>
|
|
255
|
+
<option value="5">Five</option>
|
|
256
|
+
</optgroup>
|
|
257
|
+
</select>`
|
|
258
|
+
|
|
259
|
+
let selectElement = document.getElementById('test') as HTMLSelectElement
|
|
260
|
+
let select = new Select(selectElement)
|
|
261
|
+
|
|
262
|
+
let dataOptgroup = select.getData() as Optgroup[]
|
|
263
|
+
|
|
264
|
+
expect(dataOptgroup[0].options[0].text).toBe('One')
|
|
265
|
+
|
|
266
|
+
const callback = jest.fn()
|
|
267
|
+
select.onOptionsChange = callback
|
|
268
|
+
|
|
269
|
+
let selectOption = document.getElementById('test_option') as HTMLOptionElement
|
|
270
|
+
selectOption.text = 'New One'
|
|
271
|
+
|
|
272
|
+
let dataOption = select.getData() as Optgroup[]
|
|
273
|
+
expect(dataOption[0].options[0].text).toBe('New One')
|
|
154
274
|
})
|
|
155
275
|
})
|
|
@@ -1,36 +1,42 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { kebabCase } from './helpers'
|
|
2
2
|
import { DataArray, DataArrayPartial, Optgroup, OptgroupOptional, Option } from './store'
|
|
3
3
|
|
|
4
4
|
export default class Select {
|
|
5
5
|
public select: HTMLSelectElement
|
|
6
|
-
public listen: boolean = false
|
|
7
6
|
|
|
8
7
|
// Mutation observer fields
|
|
9
|
-
public onSelectChange?: (data: DataArrayPartial) => void
|
|
10
8
|
public onValueChange?: (value: string[]) => void
|
|
9
|
+
public onDisabledChange?: (disabled: boolean) => void
|
|
10
|
+
public onOptionsChange?: (data: DataArrayPartial) => void
|
|
11
|
+
|
|
12
|
+
// Change observers
|
|
13
|
+
public listen: boolean = false
|
|
11
14
|
private observer: MutationObserver | null = null
|
|
12
15
|
|
|
13
16
|
constructor(select: HTMLSelectElement) {
|
|
14
17
|
this.select = select
|
|
18
|
+
|
|
19
|
+
// Add change event listener
|
|
20
|
+
this.select.addEventListener('change', this.valueChange.bind(this), {
|
|
21
|
+
// allow bubbling of event
|
|
22
|
+
passive: true,
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
// Initiate mutation observer
|
|
26
|
+
this.observer = new MutationObserver(this.observeCall.bind(this))
|
|
27
|
+
|
|
28
|
+
// Start listening for changes
|
|
29
|
+
this.changeListen(true)
|
|
15
30
|
}
|
|
16
31
|
|
|
17
|
-
// Set to enabled
|
|
18
32
|
public enable(): void {
|
|
19
|
-
// Disable original select but dont trigger observer
|
|
20
|
-
this.disconnectObserver()
|
|
21
33
|
this.select.disabled = false
|
|
22
|
-
this.connectObserver()
|
|
23
34
|
}
|
|
24
35
|
|
|
25
|
-
// Set to disabled
|
|
26
36
|
public disable(): void {
|
|
27
|
-
// Enable original select but dont trigger observer
|
|
28
|
-
this.disconnectObserver()
|
|
29
37
|
this.select.disabled = true
|
|
30
|
-
this.connectObserver()
|
|
31
38
|
}
|
|
32
39
|
|
|
33
|
-
// Set misc attributes on the main select element
|
|
34
40
|
public hideUI(): void {
|
|
35
41
|
this.select.tabIndex = -1
|
|
36
42
|
this.select.style.display = 'none'
|
|
@@ -43,44 +49,30 @@ export default class Select {
|
|
|
43
49
|
this.select.removeAttribute('aria-hidden')
|
|
44
50
|
}
|
|
45
51
|
|
|
46
|
-
public changeListen(
|
|
47
|
-
this.listen =
|
|
48
|
-
|
|
49
|
-
//
|
|
50
|
-
if (
|
|
51
|
-
this.
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
public changeListen(listen: boolean) {
|
|
53
|
+
this.listen = listen
|
|
54
|
+
|
|
55
|
+
// Start listening for changes
|
|
56
|
+
if (listen) {
|
|
57
|
+
if (this.observer) {
|
|
58
|
+
this.observer.observe(this.select, {
|
|
59
|
+
subtree: true, // subtree for optgroups options
|
|
60
|
+
childList: true, // children changes
|
|
61
|
+
attributes: true, // attributes changes
|
|
62
|
+
})
|
|
63
|
+
}
|
|
54
64
|
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Add change listener to original select
|
|
58
|
-
public addSelectChangeListener(func: (data: DataArrayPartial) => void): void {
|
|
59
|
-
this.onSelectChange = func
|
|
60
|
-
this.addObserver()
|
|
61
|
-
this.connectObserver()
|
|
62
|
-
this.changeListen(true) // Last start listening
|
|
63
|
-
}
|
|
64
65
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
public addValueChangeListener(func: (value: string[]) => void): void {
|
|
72
|
-
this.onValueChange = func
|
|
73
|
-
this.select.addEventListener('change', this.valueChange.bind(this), {
|
|
74
|
-
// allow bubbling of event
|
|
75
|
-
passive: true,
|
|
76
|
-
})
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
public removeValueChangeListener(): void {
|
|
80
|
-
this.onValueChange = undefined
|
|
81
|
-
this.select.removeEventListener('change', this.valueChange.bind(this))
|
|
66
|
+
// Stop listening for changes
|
|
67
|
+
if (!listen) {
|
|
68
|
+
if (this.observer) {
|
|
69
|
+
this.observer.disconnect()
|
|
70
|
+
}
|
|
71
|
+
}
|
|
82
72
|
}
|
|
83
73
|
|
|
74
|
+
// This function get triggers when the select value changes
|
|
75
|
+
// and will call the onValueChange function if it exists
|
|
84
76
|
public valueChange(ev: Event): boolean {
|
|
85
77
|
if (this.listen && this.onValueChange) {
|
|
86
78
|
this.onValueChange(this.getSelectedValues())
|
|
@@ -90,47 +82,43 @@ export default class Select {
|
|
|
90
82
|
return true
|
|
91
83
|
}
|
|
92
84
|
|
|
93
|
-
private
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
this.changeListen(false)
|
|
98
|
-
this.onSelectChange(this.getData())
|
|
99
|
-
this.changeListen(true)
|
|
85
|
+
private observeCall(mutations: MutationRecord[]): void {
|
|
86
|
+
// If we are not listeing do nothing
|
|
87
|
+
if (!this.listen) {
|
|
88
|
+
return
|
|
100
89
|
}
|
|
101
|
-
}
|
|
102
90
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
// If mutation observer already exists then disconnect and
|
|
106
|
-
if (this.observer) {
|
|
107
|
-
this.disconnectObserver()
|
|
108
|
-
this.observer = null
|
|
109
|
-
}
|
|
91
|
+
let disabledChanged = false
|
|
92
|
+
let optgroupOptionChanged = false
|
|
110
93
|
|
|
111
|
-
//
|
|
112
|
-
|
|
113
|
-
|
|
94
|
+
// Loop through mutations and check various things
|
|
95
|
+
for (const m of mutations) {
|
|
96
|
+
// Check if its the select
|
|
97
|
+
if (m.target === this.select) {
|
|
98
|
+
// Check if disabled has changed
|
|
99
|
+
if (m.attributeName === 'disabled') {
|
|
100
|
+
disabledChanged = true
|
|
101
|
+
}
|
|
102
|
+
}
|
|
114
103
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
// For now we only care about if the children change
|
|
120
|
-
childList: true,
|
|
121
|
-
|
|
122
|
-
// We dont care about attributes for now
|
|
123
|
-
// might need to add this later
|
|
124
|
-
// attributes: true,
|
|
125
|
-
// characterData: true,
|
|
126
|
-
// subtree: true,
|
|
127
|
-
})
|
|
104
|
+
// Check if its an optgroup or option
|
|
105
|
+
if (m.target.nodeName === 'OPTGROUP' || m.target.nodeName === 'OPTION') {
|
|
106
|
+
optgroupOptionChanged = true
|
|
107
|
+
}
|
|
128
108
|
}
|
|
129
|
-
}
|
|
130
109
|
|
|
131
|
-
|
|
132
|
-
if (this.
|
|
133
|
-
this.
|
|
110
|
+
// If disabled has changed then call the disabled change function
|
|
111
|
+
if (disabledChanged && this.onDisabledChange) {
|
|
112
|
+
this.changeListen(false)
|
|
113
|
+
this.onDisabledChange(this.select.disabled)
|
|
114
|
+
this.changeListen(true)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// If optgroup or option has changed then call the select change function
|
|
118
|
+
if (optgroupOptionChanged && this.onOptionsChange) {
|
|
119
|
+
this.changeListen(false)
|
|
120
|
+
this.onOptionsChange(this.getData())
|
|
121
|
+
this.changeListen(true)
|
|
134
122
|
}
|
|
135
123
|
}
|
|
136
124
|
|
|
@@ -157,7 +145,7 @@ export default class Select {
|
|
|
157
145
|
|
|
158
146
|
public getDataFromOptgroup(optgroup: HTMLOptGroupElement): OptgroupOptional {
|
|
159
147
|
let data = {
|
|
160
|
-
id:
|
|
148
|
+
id: optgroup.id,
|
|
161
149
|
label: optgroup.label,
|
|
162
150
|
selectAll: optgroup.dataset ? optgroup.dataset.selectall === 'true' : false,
|
|
163
151
|
closable: optgroup.dataset ? optgroup.dataset.closable : 'off',
|
|
@@ -177,10 +165,10 @@ export default class Select {
|
|
|
177
165
|
// From passed in option pull pieces of usable information
|
|
178
166
|
public getDataFromOption(option: HTMLOptionElement): Option {
|
|
179
167
|
return {
|
|
180
|
-
id:
|
|
168
|
+
id: option.id,
|
|
181
169
|
value: option.value,
|
|
182
170
|
text: option.text,
|
|
183
|
-
html: option.
|
|
171
|
+
html: option.dataset && option.dataset.html ? option.dataset.html : '',
|
|
184
172
|
selected: option.selected,
|
|
185
173
|
display: option.style.display === 'none' ? false : true,
|
|
186
174
|
disabled: option.disabled,
|
|
@@ -222,6 +210,9 @@ export default class Select {
|
|
|
222
210
|
}
|
|
223
211
|
|
|
224
212
|
public setSelected(value: string[]): void {
|
|
213
|
+
// Stop listening to changes
|
|
214
|
+
this.changeListen(false)
|
|
215
|
+
|
|
225
216
|
// Loop through options and set selected
|
|
226
217
|
const options = this.select.childNodes as any as (HTMLOptGroupElement | HTMLOptionElement)[]
|
|
227
218
|
for (const o of options) {
|
|
@@ -241,6 +232,9 @@ export default class Select {
|
|
|
241
232
|
option.selected = value.includes(option.value)
|
|
242
233
|
}
|
|
243
234
|
}
|
|
235
|
+
|
|
236
|
+
// Stop listening to changes
|
|
237
|
+
this.changeListen(true)
|
|
244
238
|
}
|
|
245
239
|
|
|
246
240
|
public updateSelect(id?: string, style?: string, classes?: string[]): void {
|
|
@@ -315,8 +309,12 @@ export default class Select {
|
|
|
315
309
|
|
|
316
310
|
public createOption(info: Option): HTMLOptionElement {
|
|
317
311
|
const optionEl = document.createElement('option')
|
|
318
|
-
optionEl.
|
|
319
|
-
optionEl.
|
|
312
|
+
optionEl.id = info.id
|
|
313
|
+
optionEl.value = info.value // !== '' ? info.value : info.text
|
|
314
|
+
optionEl.innerHTML = info.text
|
|
315
|
+
if (info.html !== '') {
|
|
316
|
+
optionEl.setAttribute('data-html', info.html)
|
|
317
|
+
}
|
|
320
318
|
if (info.selected) {
|
|
321
319
|
optionEl.selected = info.selected
|
|
322
320
|
}
|
|
@@ -348,9 +346,15 @@ export default class Select {
|
|
|
348
346
|
|
|
349
347
|
public destroy() {
|
|
350
348
|
this.changeListen(false)
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
this.
|
|
349
|
+
|
|
350
|
+
// Remove event change listener
|
|
351
|
+
this.select.removeEventListener('change', this.valueChange.bind(this))
|
|
352
|
+
|
|
353
|
+
// Disconnect observer and null
|
|
354
|
+
if (this.observer) {
|
|
355
|
+
this.observer.disconnect()
|
|
356
|
+
this.observer = null
|
|
357
|
+
}
|
|
354
358
|
|
|
355
359
|
// show the original select
|
|
356
360
|
this.showUI()
|
|
@@ -14,7 +14,7 @@ export default class Settings {
|
|
|
14
14
|
public intervalMove: NodeJS.Timeout | null = null
|
|
15
15
|
|
|
16
16
|
// Fields set from constructor
|
|
17
|
-
public
|
|
17
|
+
public disabled: boolean
|
|
18
18
|
public alwaysOpen: boolean
|
|
19
19
|
public showSearch: boolean
|
|
20
20
|
public searchPlaceholder: string
|
|
@@ -32,6 +32,8 @@ export default class Settings {
|
|
|
32
32
|
public minSelected: number
|
|
33
33
|
public maxSelected: number
|
|
34
34
|
public timeoutDelay: number
|
|
35
|
+
public maxValuesShown: number
|
|
36
|
+
public maxValuesMessage: string
|
|
35
37
|
|
|
36
38
|
constructor(settings?: SettingsPartial) {
|
|
37
39
|
if (!settings) {
|
|
@@ -42,7 +44,7 @@ export default class Settings {
|
|
|
42
44
|
this.style = settings.style || ''
|
|
43
45
|
this.class = settings.class || []
|
|
44
46
|
|
|
45
|
-
this.
|
|
47
|
+
this.disabled = settings.disabled !== undefined ? settings.disabled : false
|
|
46
48
|
this.alwaysOpen = settings.alwaysOpen !== undefined ? settings.alwaysOpen : false
|
|
47
49
|
this.showSearch = settings.showSearch !== undefined ? settings.showSearch : true
|
|
48
50
|
this.searchPlaceholder = settings.searchPlaceholder || 'Search'
|
|
@@ -60,5 +62,7 @@ export default class Settings {
|
|
|
60
62
|
this.minSelected = settings.minSelected || 0
|
|
61
63
|
this.maxSelected = settings.maxSelected || 1000
|
|
62
64
|
this.timeoutDelay = settings.timeoutDelay || 200
|
|
65
|
+
this.maxValuesShown = settings.maxValuesShown || 20
|
|
66
|
+
this.maxValuesMessage = settings.maxValuesMessage || '{number} selected'
|
|
63
67
|
}
|
|
64
68
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
--ss-bg-color: #ffffff;
|
|
5
5
|
--ss-font-color: #4d4d4d;
|
|
6
6
|
--ss-font-placeholder-color: #8d8d8d;
|
|
7
|
-
--ss-disabled-color: #
|
|
7
|
+
--ss-disabled-color: #dcdee2;
|
|
8
8
|
--ss-border-color: #dcdee2;
|
|
9
9
|
--ss-highlight-color: #fffb8c;
|
|
10
10
|
--ss-success-color: #00b755;
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
&.ss-disabled {
|
|
77
|
-
background-color: var(--ss-
|
|
77
|
+
background-color: var(--ss-disabled-color);
|
|
78
78
|
cursor: not-allowed;
|
|
79
79
|
|
|
80
80
|
.ss-values {
|
|
@@ -118,11 +118,27 @@
|
|
|
118
118
|
white-space: nowrap;
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
+
// Max is used to display max number of values
|
|
122
|
+
.ss-max {
|
|
123
|
+
display: flex;
|
|
124
|
+
user-select: none;
|
|
125
|
+
align-items: center;
|
|
126
|
+
width: fit-content;
|
|
127
|
+
font-size: 12px;
|
|
128
|
+
color: var(--ss-bg-color);
|
|
129
|
+
line-height: 1;
|
|
130
|
+
padding: var(--ss-spacing-s) var(--ss-spacing-m);
|
|
131
|
+
background-color: var(--ss-primary-color);
|
|
132
|
+
border-radius: var(--ss-border-radius);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Used for single select selected value
|
|
121
136
|
.ss-single {
|
|
122
137
|
display: flex;
|
|
123
138
|
margin: auto 0px auto var(--ss-spacing-s);
|
|
124
139
|
}
|
|
125
140
|
|
|
141
|
+
// Used for the selected values
|
|
126
142
|
.ss-value {
|
|
127
143
|
display: flex;
|
|
128
144
|
user-select: none;
|
|
@@ -231,6 +247,7 @@
|
|
|
231
247
|
transition: transform var(--ss-animation-timing), opacity var(--ss-animation-timing);
|
|
232
248
|
opacity: 0;
|
|
233
249
|
transform: scaleY(0);
|
|
250
|
+
transform-origin: center top;
|
|
234
251
|
overflow: hidden;
|
|
235
252
|
z-index: 10000;
|
|
236
253
|
|
|
@@ -240,6 +257,7 @@
|
|
|
240
257
|
}
|
|
241
258
|
|
|
242
259
|
&.ss-open-above {
|
|
260
|
+
flex-direction: column-reverse;
|
|
243
261
|
opacity: 1;
|
|
244
262
|
transform: scaleY(1);
|
|
245
263
|
transform-origin: center bottom;
|
|
@@ -456,26 +474,31 @@
|
|
|
456
474
|
.ss-option {
|
|
457
475
|
display: flex;
|
|
458
476
|
padding: var(--ss-spacing-m) var(--ss-spacing-l) var(--ss-spacing-m) var(--ss-spacing-l);
|
|
477
|
+
color: var(--ss-font-color);
|
|
459
478
|
cursor: pointer;
|
|
460
479
|
user-select: none;
|
|
461
480
|
|
|
462
|
-
&:hover
|
|
463
|
-
|
|
481
|
+
&:hover {
|
|
482
|
+
color: var(--ss-bg-color);
|
|
483
|
+
background-color: var(--ss-primary-color);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
&.ss-highlighted,
|
|
487
|
+
&:not(.ss-disabled).ss-selected {
|
|
464
488
|
color: var(--ss-bg-color);
|
|
465
489
|
background-color: var(--ss-primary-color);
|
|
466
490
|
}
|
|
467
491
|
|
|
468
492
|
&.ss-disabled {
|
|
469
493
|
cursor: not-allowed;
|
|
470
|
-
color: var(--ss-disabled-color);
|
|
471
|
-
background-color: var(--ss-bg-color);
|
|
472
|
-
}
|
|
494
|
+
background-color: var(--ss-disabled-color);
|
|
473
495
|
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
496
|
+
&:hover {
|
|
497
|
+
color: var(--ss-font-color);
|
|
498
|
+
}
|
|
477
499
|
}
|
|
478
500
|
|
|
501
|
+
// Sub div wrapper for highlighting text
|
|
479
502
|
.ss-search-highlight {
|
|
480
503
|
background-color: var(--ss-highlight-color);
|
|
481
504
|
}
|
|
@@ -117,6 +117,28 @@ describe('store module', () => {
|
|
|
117
117
|
expect((data[0] as Option).selected).toBe(true)
|
|
118
118
|
})
|
|
119
119
|
|
|
120
|
+
test('set data and set selected to empty string', () => {
|
|
121
|
+
let store = new Store('single', [
|
|
122
|
+
{
|
|
123
|
+
text: 'all',
|
|
124
|
+
value: '',
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
text: 'Value 1',
|
|
128
|
+
value: '1',
|
|
129
|
+
selected: true,
|
|
130
|
+
},
|
|
131
|
+
])
|
|
132
|
+
store.setSelectedBy('value', [''])
|
|
133
|
+
|
|
134
|
+
let data = store.getData()
|
|
135
|
+
|
|
136
|
+
// Make sure data has one item and that it has the correct text
|
|
137
|
+
expect(data.length).toBe(2)
|
|
138
|
+
expect((data[0] as Option).text).toBe('all')
|
|
139
|
+
expect((data[0] as Option).selected).toBe(true)
|
|
140
|
+
})
|
|
141
|
+
|
|
120
142
|
test('set data and set selected by value multiple for single element', () => {
|
|
121
143
|
let store = new Store('single', [
|
|
122
144
|
{
|
|
@@ -48,6 +48,7 @@ export default class Render {
|
|
|
48
48
|
placeholder: string;
|
|
49
49
|
values: string;
|
|
50
50
|
single: string;
|
|
51
|
+
max: string;
|
|
51
52
|
value: string;
|
|
52
53
|
valueText: string;
|
|
53
54
|
valueDelete: string;
|
|
@@ -112,5 +113,5 @@ export default class Render {
|
|
|
112
113
|
moveContentAbove(): void;
|
|
113
114
|
moveContentBelow(): void;
|
|
114
115
|
ensureElementInView(container: HTMLElement, element: HTMLElement): void;
|
|
115
|
-
putContent(
|
|
116
|
+
putContent(): 'up' | 'down';
|
|
116
117
|
}
|