slim-select 2.8.2 → 2.9.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/.prettierignore +1 -0
- package/.prettierrc +4 -3
- package/README.md +2 -0
- package/dist/classes.d.ts +43 -0
- package/dist/helpers.d.ts +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/render.d.ts +4 -44
- package/dist/select.d.ts +4 -2
- package/dist/settings.d.ts +2 -1
- package/dist/slimselect.cjs.js +248 -120
- package/dist/slimselect.css +1 -1
- package/dist/slimselect.css.map +1 -1
- package/dist/slimselect.es.js +248 -120
- package/dist/slimselect.global.js +248 -120
- package/dist/slimselect.js +248 -120
- package/dist/slimselect.min.js +1 -1
- package/dist/slimselect.umd.js +248 -120
- package/dist/slimselect.umd.min.js +1 -1
- package/dist/store.d.ts +4 -2
- package/index.html +1 -4
- package/jest.config.js +6 -0
- package/package.json +30 -39
- package/src/slim-select/classes.test.ts +72 -0
- package/src/slim-select/classes.ts +109 -0
- package/src/slim-select/helpers.test.ts +160 -0
- package/src/slim-select/helpers.ts +3 -12
- package/src/slim-select/index.test.ts +109 -16
- package/src/slim-select/index.ts +41 -12
- package/src/slim-select/render.test.ts +1169 -18
- package/src/slim-select/render.ts +75 -96
- package/src/slim-select/rollup.config.mjs +28 -28
- package/src/slim-select/select.test.ts +306 -156
- package/src/slim-select/select.ts +69 -20
- package/src/slim-select/settings.test.ts +257 -0
- package/src/slim-select/settings.ts +4 -0
- package/src/slim-select/slimselect.scss +7 -3
- package/src/slim-select/store.test.ts +986 -235
- package/src/slim-select/store.ts +70 -28
- package/src/{vue/slimselect.vue → slim-select/vue.vue} +19 -17
- package/tsconfig.json +2 -3
- package/src/react/.eslintignore +0 -2
- package/src/react/.eslintrc.cjs +0 -24
- package/src/react/index.html +0 -14
- package/src/react/jestconfig.json +0 -11
- package/src/react/package.json +0 -32
- package/src/react/src/frameworkpage.tsx +0 -133
- package/src/react/src/index.ts +0 -3
- package/src/react/src/slimselect.tsx +0 -148
- package/src/react/tests/slimselect.test.tsx +0 -52
- package/src/react/tsconfig.json +0 -37
- package/src/react/tsconfig.node.json +0 -10
- package/src/react/vite.config.ts +0 -55
- package/src/vue/README.md +0 -48
- package/src/vue/dist/slim-select/helpers.d.ts +0 -5
- package/src/vue/dist/slim-select/index.d.ts +0 -46
- package/src/vue/dist/slim-select/render.d.ts +0 -120
- package/src/vue/dist/slim-select/select.d.ts +0 -28
- package/src/vue/dist/slim-select/settings.d.ts +0 -34
- package/src/vue/dist/slim-select/store.d.ts +0 -80
- package/src/vue/dist/slimselectvue.es.js +0 -1978
- package/src/vue/dist/slimselectvue.global.js +0 -1981
- package/src/vue/dist/slimselectvue.ssr.js +0 -1980
- package/src/vue/dist/vue/hello.d.ts +0 -2
- package/src/vue/dist/vue/slimselect.vue.d.ts +0 -326
- package/src/vue/hello.ts +0 -5
- package/src/vue/package.json +0 -28
- package/src/vue/rollup.config.mjs +0 -44
- package/src/vue/tsconfig.json +0 -14
- /package/{vite.config.ts → vite.config.mts} +0 -0
|
@@ -5,7 +5,7 @@ export default class Select {
|
|
|
5
5
|
public select: HTMLSelectElement
|
|
6
6
|
|
|
7
7
|
// Mutation observer fields
|
|
8
|
-
public onValueChange?: (value:
|
|
8
|
+
public onValueChange?: (value: Option[]) => void
|
|
9
9
|
public onClassChange?: (classes: string[]) => void
|
|
10
10
|
public onDisabledChange?: (disabled: boolean) => void
|
|
11
11
|
public onOptionsChange?: (data: DataArrayPartial) => void
|
|
@@ -21,7 +21,7 @@ export default class Select {
|
|
|
21
21
|
// Add change event listener
|
|
22
22
|
this.select.addEventListener('change', this.valueChange, {
|
|
23
23
|
// allow bubbling of event
|
|
24
|
-
passive: true
|
|
24
|
+
passive: true
|
|
25
25
|
})
|
|
26
26
|
|
|
27
27
|
// Initiate mutation observer
|
|
@@ -60,7 +60,7 @@ export default class Select {
|
|
|
60
60
|
this.observer.observe(this.select, {
|
|
61
61
|
subtree: true, // subtree for optgroups options
|
|
62
62
|
childList: true, // children changes
|
|
63
|
-
attributes: true
|
|
63
|
+
attributes: true // attributes changes
|
|
64
64
|
})
|
|
65
65
|
}
|
|
66
66
|
}
|
|
@@ -77,7 +77,7 @@ export default class Select {
|
|
|
77
77
|
// and will call the onValueChange function if it exists
|
|
78
78
|
public valueChange(ev: Event): boolean {
|
|
79
79
|
if (this.listen && this.onValueChange) {
|
|
80
|
-
this.onValueChange(this.
|
|
80
|
+
this.onValueChange(this.getSelectedOptions())
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
// Allow bubbling back to other change event listeners
|
|
@@ -85,7 +85,7 @@ export default class Select {
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
private observeCall(mutations: MutationRecord[]): void {
|
|
88
|
-
// If we are not
|
|
88
|
+
// If we are not listening, do nothing.
|
|
89
89
|
if (!this.listen) {
|
|
90
90
|
return
|
|
91
91
|
}
|
|
@@ -107,6 +107,19 @@ export default class Select {
|
|
|
107
107
|
if (m.attributeName === 'class') {
|
|
108
108
|
classChanged = true
|
|
109
109
|
}
|
|
110
|
+
|
|
111
|
+
if (m.type === 'childList') {
|
|
112
|
+
for (const n of m.addedNodes) {
|
|
113
|
+
if (n.nodeName === 'OPTION' && (<HTMLOptionElement>n).value === this.select.value) {
|
|
114
|
+
// we added a new option that's now the select value
|
|
115
|
+
this.select.dispatchEvent(new Event('change'))
|
|
116
|
+
break
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// options changed, so we need the optionsChange event to fire
|
|
121
|
+
optgroupOptionChanged = true
|
|
122
|
+
}
|
|
110
123
|
}
|
|
111
124
|
|
|
112
125
|
// Check if its an optgroup or option
|
|
@@ -163,7 +176,7 @@ export default class Select {
|
|
|
163
176
|
selectAll: optgroup.dataset ? optgroup.dataset.selectall === 'true' : false,
|
|
164
177
|
selectAllText: optgroup.dataset ? optgroup.dataset.selectalltext : 'Select all',
|
|
165
178
|
closable: optgroup.dataset ? optgroup.dataset.closable : 'off',
|
|
166
|
-
options: []
|
|
179
|
+
options: []
|
|
167
180
|
} as OptgroupOptional
|
|
168
181
|
|
|
169
182
|
const options = optgroup.childNodes as any as HTMLOptionElement[]
|
|
@@ -184,29 +197,29 @@ export default class Select {
|
|
|
184
197
|
text: option.text,
|
|
185
198
|
html: option.dataset && option.dataset.html ? option.dataset.html : '',
|
|
186
199
|
selected: option.selected,
|
|
187
|
-
display: option.style.display
|
|
200
|
+
display: option.style.display !== 'none',
|
|
188
201
|
disabled: option.disabled,
|
|
189
202
|
mandatory: option.dataset ? option.dataset.mandatory === 'true' : false,
|
|
190
203
|
placeholder: option.dataset.placeholder === 'true',
|
|
191
204
|
class: option.className,
|
|
192
205
|
style: option.style.cssText,
|
|
193
|
-
data: option.dataset
|
|
206
|
+
data: option.dataset
|
|
194
207
|
} as Option
|
|
195
208
|
}
|
|
196
209
|
|
|
197
|
-
public
|
|
198
|
-
let
|
|
210
|
+
public getSelectedOptions(): Option[] {
|
|
211
|
+
let options = []
|
|
199
212
|
|
|
200
213
|
// Loop through options and set selected
|
|
201
|
-
const
|
|
202
|
-
for (const o of
|
|
214
|
+
const opts = this.select.childNodes as any as (HTMLOptGroupElement | HTMLOptionElement)[]
|
|
215
|
+
for (const o of opts) {
|
|
203
216
|
if (o.nodeName === 'OPTGROUP') {
|
|
204
217
|
const optgroupOptions = o.childNodes as any as HTMLOptionElement[]
|
|
205
218
|
for (const oo of optgroupOptions) {
|
|
206
219
|
if (oo.nodeName === 'OPTION') {
|
|
207
220
|
const option = oo as HTMLOptionElement
|
|
208
221
|
if (option.selected) {
|
|
209
|
-
|
|
222
|
+
options.push(this.getDataFromOption(option))
|
|
210
223
|
}
|
|
211
224
|
}
|
|
212
225
|
}
|
|
@@ -215,15 +228,51 @@ export default class Select {
|
|
|
215
228
|
if (o.nodeName === 'OPTION') {
|
|
216
229
|
const option = o as HTMLOptionElement
|
|
217
230
|
if (option.selected) {
|
|
218
|
-
|
|
231
|
+
options.push(this.getDataFromOption(option))
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return options
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
public getSelectedValues(): string[] {
|
|
240
|
+
return this.getSelectedOptions().map((option) => option.value)
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
public setSelected(ids: string[]): void {
|
|
244
|
+
// Stop listening to changes
|
|
245
|
+
this.changeListen(false)
|
|
246
|
+
|
|
247
|
+
// Loop through options and set selected
|
|
248
|
+
const options = this.select.childNodes as any as (HTMLOptGroupElement | HTMLOptionElement)[]
|
|
249
|
+
for (const o of options) {
|
|
250
|
+
if (o.nodeName === 'OPTGROUP') {
|
|
251
|
+
const optgroup = o as HTMLOptGroupElement
|
|
252
|
+
const optgroupOptions = optgroup.childNodes as any as HTMLOptionElement[]
|
|
253
|
+
for (const oo of optgroupOptions) {
|
|
254
|
+
if (oo.nodeName === 'OPTION') {
|
|
255
|
+
const option = oo as HTMLOptionElement
|
|
256
|
+
option.selected = ids.includes(option.id)
|
|
257
|
+
}
|
|
219
258
|
}
|
|
220
259
|
}
|
|
260
|
+
|
|
261
|
+
if (o.nodeName === 'OPTION') {
|
|
262
|
+
const option = o as HTMLOptionElement
|
|
263
|
+
option.selected = ids.includes(option.id)
|
|
264
|
+
}
|
|
221
265
|
}
|
|
222
266
|
|
|
223
|
-
|
|
267
|
+
// Stop listening to changes
|
|
268
|
+
this.changeListen(true)
|
|
224
269
|
}
|
|
225
270
|
|
|
226
|
-
|
|
271
|
+
// Set selected options by value instead of id
|
|
272
|
+
// This is useful when the id is not known
|
|
273
|
+
// and only the value is known
|
|
274
|
+
// but the value is not unique and can be duplicated
|
|
275
|
+
public setSelectedByValue(values: string[]): void {
|
|
227
276
|
// Stop listening to changes
|
|
228
277
|
this.changeListen(false)
|
|
229
278
|
|
|
@@ -236,14 +285,14 @@ export default class Select {
|
|
|
236
285
|
for (const oo of optgroupOptions) {
|
|
237
286
|
if (oo.nodeName === 'OPTION') {
|
|
238
287
|
const option = oo as HTMLOptionElement
|
|
239
|
-
option.selected =
|
|
288
|
+
option.selected = values.includes(option.value)
|
|
240
289
|
}
|
|
241
290
|
}
|
|
242
291
|
}
|
|
243
292
|
|
|
244
293
|
if (o.nodeName === 'OPTION') {
|
|
245
294
|
const option = o as HTMLOptionElement
|
|
246
|
-
option.selected =
|
|
295
|
+
option.selected = values.includes(option.value)
|
|
247
296
|
}
|
|
248
297
|
}
|
|
249
298
|
|
|
@@ -297,7 +346,7 @@ export default class Select {
|
|
|
297
346
|
}
|
|
298
347
|
|
|
299
348
|
// Trigger change event on original select
|
|
300
|
-
this.select.dispatchEvent(new Event('change'))
|
|
349
|
+
this.select.dispatchEvent(new Event('change', { bubbles: true }))
|
|
301
350
|
|
|
302
351
|
// Start listening to changes
|
|
303
352
|
this.changeListen(true)
|
|
@@ -335,7 +384,7 @@ export default class Select {
|
|
|
335
384
|
if (info.disabled) {
|
|
336
385
|
optionEl.disabled = true
|
|
337
386
|
}
|
|
338
|
-
if (info.display
|
|
387
|
+
if (!info.display) {
|
|
339
388
|
optionEl.style.display = 'none'
|
|
340
389
|
}
|
|
341
390
|
if (info.placeholder) {
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
import { describe, expect, test } from '@jest/globals'
|
|
4
|
+
import Settings from './settings'
|
|
5
|
+
import Select from './select'
|
|
6
|
+
import { Option, Optgroup } from './store'
|
|
7
|
+
|
|
8
|
+
const defaultSettings: { [key: string]: any } = {
|
|
9
|
+
id: 'ss-qucyuytu',
|
|
10
|
+
style: '',
|
|
11
|
+
class: [],
|
|
12
|
+
isMultiple: false,
|
|
13
|
+
isOpen: false,
|
|
14
|
+
isFullOpen: false,
|
|
15
|
+
intervalMove: null,
|
|
16
|
+
disabled: false,
|
|
17
|
+
alwaysOpen: false,
|
|
18
|
+
showSearch: true,
|
|
19
|
+
focusSearch: true,
|
|
20
|
+
ariaLabel: 'Combobox',
|
|
21
|
+
searchPlaceholder: 'Search',
|
|
22
|
+
searchText: 'No Results',
|
|
23
|
+
searchingText: 'Searching...',
|
|
24
|
+
searchHighlight: false,
|
|
25
|
+
closeOnSelect: true,
|
|
26
|
+
contentLocation: HTMLBodyElement,
|
|
27
|
+
contentPosition: 'absolute',
|
|
28
|
+
openPosition: 'auto',
|
|
29
|
+
placeholderText: 'Select Value',
|
|
30
|
+
allowDeselect: false,
|
|
31
|
+
hideSelected: false,
|
|
32
|
+
keepOrder: false,
|
|
33
|
+
showOptionTooltips: false,
|
|
34
|
+
minSelected: 0,
|
|
35
|
+
maxSelected: 1000,
|
|
36
|
+
timeoutDelay: 200,
|
|
37
|
+
maxValuesShown: 20,
|
|
38
|
+
maxValuesMessage: '{number} selected'
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
describe('Settings module', () => {
|
|
42
|
+
let select: Select
|
|
43
|
+
|
|
44
|
+
beforeEach(() => {
|
|
45
|
+
const selectElement = document.createElement('select')
|
|
46
|
+
select = new Select(selectElement)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
test('empty constructor returns default settings', () => {
|
|
50
|
+
// Convert to unknown and then to custom object to prevent TS from throwing errors
|
|
51
|
+
const settings = new Settings() as unknown as { [key: string]: string }
|
|
52
|
+
Object.keys(defaultSettings).forEach((key) => {
|
|
53
|
+
if (key === 'id') {
|
|
54
|
+
expect(settings[key].substring(0, 3)).toBe('ss-')
|
|
55
|
+
} else if (key === 'contentLocation') {
|
|
56
|
+
expect(settings[key]).toBeInstanceOf(defaultSettings[key])
|
|
57
|
+
} else {
|
|
58
|
+
expect(settings[key]).toStrictEqual(defaultSettings[key])
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
test('settings can be overwritten via the constructor', () => {
|
|
64
|
+
const customSettings = {
|
|
65
|
+
disabled: true,
|
|
66
|
+
alwaysOpen: true,
|
|
67
|
+
showSearch: false,
|
|
68
|
+
focusSearch: true,
|
|
69
|
+
searchHighlight: true,
|
|
70
|
+
closeOnSelect: false,
|
|
71
|
+
placeholderText: 'new placeholder',
|
|
72
|
+
hideSelected: true,
|
|
73
|
+
keepOrder: true,
|
|
74
|
+
showOptionTooltips: true
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const settingsWithOverride = {
|
|
78
|
+
...defaultSettings,
|
|
79
|
+
...customSettings
|
|
80
|
+
} as unknown as { [key: string]: any }
|
|
81
|
+
|
|
82
|
+
// Convert to unknown and then to custom object to prevent TS from throwing errors
|
|
83
|
+
const settings = new Settings(customSettings) as unknown as { [key: string]: any }
|
|
84
|
+
Object.keys(settingsWithOverride).forEach((key) => {
|
|
85
|
+
if (key === 'id') {
|
|
86
|
+
expect(settings[key].substring(0, 3)).toBe('ss-')
|
|
87
|
+
} else if (key === 'contentLocation') {
|
|
88
|
+
expect(settings[key]).toBeInstanceOf(defaultSettings[key])
|
|
89
|
+
} else {
|
|
90
|
+
expect(settings[key]).toStrictEqual(settingsWithOverride[key])
|
|
91
|
+
}
|
|
92
|
+
})
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
test('enable', () => {
|
|
96
|
+
select.select.disabled = true
|
|
97
|
+
|
|
98
|
+
select.enable()
|
|
99
|
+
expect(select.select.disabled).toBe(false)
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
test('disable', () => {
|
|
103
|
+
select.select.disabled = false
|
|
104
|
+
|
|
105
|
+
select.disable()
|
|
106
|
+
expect(select.select.disabled).toBe(true)
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
test('showUI', () => {
|
|
110
|
+
select.select.setAttribute('tabindex', '1')
|
|
111
|
+
select.select.setAttribute('aria-hidden', 'true')
|
|
112
|
+
select.select.style.display = 'none'
|
|
113
|
+
|
|
114
|
+
select.showUI()
|
|
115
|
+
expect(select.select.getAttribute('tabindex')).toBeFalsy()
|
|
116
|
+
expect(select.select.getAttribute('aria-hidden')).toBeFalsy()
|
|
117
|
+
expect(select.select.style.display).toBeFalsy()
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
describe('createOptgroup', () => {
|
|
121
|
+
test('group gets created correctly', () => {
|
|
122
|
+
const optGroup = new Optgroup({
|
|
123
|
+
label: 'test',
|
|
124
|
+
options: [
|
|
125
|
+
{
|
|
126
|
+
text: 'opt 1'
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
text: 'opt 2'
|
|
130
|
+
}
|
|
131
|
+
]
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
const optGroupElement = select.createOptgroup(optGroup)
|
|
135
|
+
|
|
136
|
+
expect(optGroupElement).toBeInstanceOf(HTMLOptGroupElement)
|
|
137
|
+
expect(optGroupElement.children).toHaveLength(2)
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
test('selectAll get set correctly', () => {
|
|
141
|
+
const optGroup = new Optgroup({
|
|
142
|
+
label: 'test',
|
|
143
|
+
selectAll: true,
|
|
144
|
+
options: [
|
|
145
|
+
{
|
|
146
|
+
text: 'opt 1'
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
text: 'opt 2'
|
|
150
|
+
}
|
|
151
|
+
]
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
const optGroupElement = select.createOptgroup(optGroup)
|
|
155
|
+
|
|
156
|
+
expect(optGroupElement).toBeInstanceOf(HTMLOptGroupElement)
|
|
157
|
+
expect(optGroupElement.dataset.selectAll).toBe('true')
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
test('closable get set correctly', () => {
|
|
161
|
+
const optGroup = new Optgroup({
|
|
162
|
+
label: 'test',
|
|
163
|
+
closable: 'open',
|
|
164
|
+
options: [
|
|
165
|
+
{
|
|
166
|
+
text: 'opt 1'
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
text: 'opt 2'
|
|
170
|
+
}
|
|
171
|
+
]
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
const optGroupElement = select.createOptgroup(optGroup)
|
|
175
|
+
|
|
176
|
+
expect(optGroupElement).toBeInstanceOf(HTMLOptGroupElement)
|
|
177
|
+
expect(optGroupElement.dataset.closable).toBe(optGroup.closable)
|
|
178
|
+
})
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
describe('createOption', () => {
|
|
182
|
+
test('correct content is set', () => {
|
|
183
|
+
const option = new Option({ text: 'opt' })
|
|
184
|
+
const optionElement = select.createOption(option)
|
|
185
|
+
|
|
186
|
+
expect(optionElement).toBeInstanceOf(HTMLOptionElement)
|
|
187
|
+
expect(optionElement.id).toBe(option.id)
|
|
188
|
+
expect(optionElement.textContent).toBe(option.text)
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
test('HTML is set as data attribute', () => {
|
|
192
|
+
const option = new Option({ text: 'opt', html: '<h1>opt</h1>' })
|
|
193
|
+
const optionElement = select.createOption(option)
|
|
194
|
+
|
|
195
|
+
expect(optionElement.dataset.html).toBe(option.html)
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
test('disabled sets disabled property correctly', () => {
|
|
199
|
+
const option = new Option({ text: 'opt', disabled: true })
|
|
200
|
+
const optionElement = select.createOption(option)
|
|
201
|
+
|
|
202
|
+
expect(optionElement.disabled).toBe(true)
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
test('display false sets inline style correctly', () => {
|
|
206
|
+
const option = new Option({ text: 'opt', display: false })
|
|
207
|
+
const optionElement = select.createOption(option)
|
|
208
|
+
|
|
209
|
+
expect(optionElement.style.display).toBe('none')
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
test('placeholder and mandatory set data attributes correctly', () => {
|
|
213
|
+
const option = new Option({
|
|
214
|
+
text: 'opt',
|
|
215
|
+
placeholder: true,
|
|
216
|
+
mandatory: true
|
|
217
|
+
})
|
|
218
|
+
const optionElement = select.createOption(option)
|
|
219
|
+
|
|
220
|
+
expect(optionElement.dataset.placeholder).toBeTruthy()
|
|
221
|
+
expect(optionElement.dataset.mandatory).toBeTruthy()
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
test('class sets CSS classes correctly', () => {
|
|
225
|
+
const option = new Option({
|
|
226
|
+
text: 'opt',
|
|
227
|
+
class: 'class0 class1 class2'
|
|
228
|
+
})
|
|
229
|
+
const optionElement = select.createOption(option)
|
|
230
|
+
|
|
231
|
+
expect(optionElement.classList.contains('class0')).toBe(true)
|
|
232
|
+
expect(optionElement.classList.contains('class1')).toBe(true)
|
|
233
|
+
expect(optionElement.classList.contains('class2')).toBe(true)
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
test('custom data attributes are set correctly', () => {
|
|
237
|
+
const option = new Option({
|
|
238
|
+
text: 'opt',
|
|
239
|
+
data: {
|
|
240
|
+
test0: 'a',
|
|
241
|
+
test1: 'b'
|
|
242
|
+
}
|
|
243
|
+
})
|
|
244
|
+
const optionElement = select.createOption(option)
|
|
245
|
+
|
|
246
|
+
expect(optionElement.dataset.test0).toBe('a')
|
|
247
|
+
expect(optionElement.dataset.test1).toBe('b')
|
|
248
|
+
})
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
test('destroy', () => {
|
|
252
|
+
select.destroy()
|
|
253
|
+
|
|
254
|
+
expect((<any>select).observer).toBeFalsy()
|
|
255
|
+
expect('id' in select.select.dataset).toBeFalsy()
|
|
256
|
+
})
|
|
257
|
+
})
|
|
@@ -17,6 +17,7 @@ export default class Settings {
|
|
|
17
17
|
public disabled: boolean
|
|
18
18
|
public alwaysOpen: boolean
|
|
19
19
|
public showSearch: boolean
|
|
20
|
+
public focusSearch: boolean
|
|
20
21
|
public ariaLabel: string
|
|
21
22
|
public searchPlaceholder: string
|
|
22
23
|
public searchText: string
|
|
@@ -36,6 +37,7 @@ export default class Settings {
|
|
|
36
37
|
public timeoutDelay: number
|
|
37
38
|
public maxValuesShown: number
|
|
38
39
|
public maxValuesMessage: string
|
|
40
|
+
public addableText: string
|
|
39
41
|
|
|
40
42
|
constructor(settings?: SettingsPartial) {
|
|
41
43
|
if (!settings) {
|
|
@@ -49,6 +51,7 @@ export default class Settings {
|
|
|
49
51
|
this.disabled = settings.disabled !== undefined ? settings.disabled : false
|
|
50
52
|
this.alwaysOpen = settings.alwaysOpen !== undefined ? settings.alwaysOpen : false
|
|
51
53
|
this.showSearch = settings.showSearch !== undefined ? settings.showSearch : true
|
|
54
|
+
this.focusSearch = settings.focusSearch !== undefined ? settings.focusSearch : true
|
|
52
55
|
this.ariaLabel = settings.ariaLabel || 'Combobox'
|
|
53
56
|
this.searchPlaceholder = settings.searchPlaceholder || 'Search'
|
|
54
57
|
this.searchText = settings.searchText || 'No Results'
|
|
@@ -68,5 +71,6 @@ export default class Settings {
|
|
|
68
71
|
this.timeoutDelay = settings.timeoutDelay || 200
|
|
69
72
|
this.maxValuesShown = settings.maxValuesShown || 20
|
|
70
73
|
this.maxValuesMessage = settings.maxValuesMessage || '{number} selected'
|
|
74
|
+
this.addableText = settings.addableText || 'Press "Enter" to add {value}'
|
|
71
75
|
}
|
|
72
76
|
}
|
|
@@ -199,7 +199,7 @@
|
|
|
199
199
|
justify-content: center;
|
|
200
200
|
width: fit-content;
|
|
201
201
|
height: auto;
|
|
202
|
-
|
|
202
|
+
padding: 0 var(--ss-spacing-m) 0 var(--ss-spacing-m);
|
|
203
203
|
|
|
204
204
|
svg {
|
|
205
205
|
width: 8px;
|
|
@@ -247,7 +247,9 @@
|
|
|
247
247
|
box-sizing: border-box;
|
|
248
248
|
border: solid 1px var(--ss-border-color);
|
|
249
249
|
background-color: var(--ss-bg-color);
|
|
250
|
-
transition:
|
|
250
|
+
transition:
|
|
251
|
+
transform var(--ss-animation-timing),
|
|
252
|
+
opacity var(--ss-animation-timing);
|
|
251
253
|
opacity: 0;
|
|
252
254
|
transform: scaleY(0);
|
|
253
255
|
transform-origin: center top;
|
|
@@ -469,8 +471,9 @@
|
|
|
469
471
|
}
|
|
470
472
|
|
|
471
473
|
.ss-option {
|
|
472
|
-
display:
|
|
474
|
+
display: block; // Important for text with mark element highlight
|
|
473
475
|
padding: var(--ss-spacing-m) var(--ss-spacing-l) var(--ss-spacing-m) var(--ss-spacing-l);
|
|
476
|
+
white-space: normal;
|
|
474
477
|
color: var(--ss-font-color);
|
|
475
478
|
cursor: pointer;
|
|
476
479
|
user-select: none;
|
|
@@ -497,6 +500,7 @@
|
|
|
497
500
|
|
|
498
501
|
// Sub div wrapper for highlighting text
|
|
499
502
|
.ss-search-highlight {
|
|
503
|
+
display: inline-block;
|
|
500
504
|
background-color: var(--ss-highlight-color);
|
|
501
505
|
}
|
|
502
506
|
}
|