slim-select 2.8.1 → 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 -41
- 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
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @jest-environment jsdom
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
'use strict'
|
|
6
|
+
|
|
7
|
+
import { describe, expect, test } from '@jest/globals'
|
|
8
|
+
import { hasClassInTree, debounce, isEqual, kebabCase } from './helpers'
|
|
9
|
+
|
|
10
|
+
describe('helpers module', () => {
|
|
11
|
+
describe('hasClassInTree', () => {
|
|
12
|
+
test('single element does not have class', () => {
|
|
13
|
+
const element = document.createElement('div')
|
|
14
|
+
element.className = 'invalid-class'
|
|
15
|
+
|
|
16
|
+
expect(hasClassInTree(element, 'test-class')).toBeNull()
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
test('single element has class', () => {
|
|
20
|
+
const element = document.createElement('div')
|
|
21
|
+
element.className = 'test-class'
|
|
22
|
+
|
|
23
|
+
expect(hasClassInTree(element, 'test-class')).toBe(element)
|
|
24
|
+
|
|
25
|
+
element.classList.add('class-2', 'class-3')
|
|
26
|
+
expect(hasClassInTree(element, 'test-class')).toBe(element)
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
test('single element has class as data id', () => {
|
|
30
|
+
const element = document.createElement('div')
|
|
31
|
+
element.dataset.id = 'test-class'
|
|
32
|
+
|
|
33
|
+
expect(hasClassInTree(element, 'test-class')).toBe(element)
|
|
34
|
+
|
|
35
|
+
element.classList.add('class-2', 'class-3')
|
|
36
|
+
expect(hasClassInTree(element, 'test-class')).toBe(element)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
test('parent element does not have class', () => {
|
|
40
|
+
const element = document.createElement('div')
|
|
41
|
+
element.className = 'invalid-class'
|
|
42
|
+
const child = document.createElement('div')
|
|
43
|
+
element.appendChild(child)
|
|
44
|
+
|
|
45
|
+
expect(hasClassInTree(child, 'test-class')).toBeNull()
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
test('parent element has class', () => {
|
|
49
|
+
const element = document.createElement('div')
|
|
50
|
+
element.className = 'test-class'
|
|
51
|
+
const child = document.createElement('div')
|
|
52
|
+
element.appendChild(child)
|
|
53
|
+
|
|
54
|
+
expect(hasClassInTree(child, 'test-class')).toBe(element)
|
|
55
|
+
|
|
56
|
+
element.classList.add('class-2', 'class-3')
|
|
57
|
+
expect(hasClassInTree(child, 'test-class')).toBe(element)
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
test('parent element has class as data id', () => {
|
|
61
|
+
const element = document.createElement('div')
|
|
62
|
+
element.dataset.id = 'test-class'
|
|
63
|
+
|
|
64
|
+
const child = document.createElement('div')
|
|
65
|
+
element.appendChild(child)
|
|
66
|
+
|
|
67
|
+
expect(hasClassInTree(child, 'test-class')).toBe(element)
|
|
68
|
+
|
|
69
|
+
element.classList.add('class-2', 'class-3')
|
|
70
|
+
expect(hasClassInTree(child, 'test-class')).toBe(element)
|
|
71
|
+
})
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
describe('debounce', () => {
|
|
75
|
+
test('debounce calls function after default timeout', async () => {
|
|
76
|
+
const callback = jest.fn()
|
|
77
|
+
const debounced_function = debounce(callback)
|
|
78
|
+
debounced_function()
|
|
79
|
+
|
|
80
|
+
await new Promise((r) => setTimeout(r, 100))
|
|
81
|
+
|
|
82
|
+
expect(callback).toHaveBeenCalled()
|
|
83
|
+
expect(callback).toHaveBeenCalledTimes(1)
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
test('debounce calls function after higher timeout', async () => {
|
|
87
|
+
const callback = jest.fn()
|
|
88
|
+
const debounced_function = debounce(callback, 100)
|
|
89
|
+
debounced_function()
|
|
90
|
+
|
|
91
|
+
await new Promise((r) => setTimeout(r, 50))
|
|
92
|
+
expect(callback).not.toHaveBeenCalled()
|
|
93
|
+
|
|
94
|
+
await new Promise((r) => setTimeout(r, 50))
|
|
95
|
+
expect(callback).toHaveBeenCalled()
|
|
96
|
+
expect(callback).toHaveBeenCalledTimes(1)
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
test('debounce calls function after lower timeout', async () => {
|
|
100
|
+
const callback = jest.fn()
|
|
101
|
+
const debounced_function = debounce(callback, 10)
|
|
102
|
+
debounced_function()
|
|
103
|
+
|
|
104
|
+
await new Promise((r) => setTimeout(r, 5))
|
|
105
|
+
expect(callback).not.toHaveBeenCalled()
|
|
106
|
+
|
|
107
|
+
await new Promise((r) => setTimeout(r, 5))
|
|
108
|
+
expect(callback).toHaveBeenCalled()
|
|
109
|
+
expect(callback).toHaveBeenCalledTimes(1)
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
test('debounce respects inmediate setting', () => {
|
|
113
|
+
const callback = jest.fn()
|
|
114
|
+
const debounced_function = debounce(callback, 1000, true)
|
|
115
|
+
debounced_function()
|
|
116
|
+
|
|
117
|
+
expect(callback).toHaveBeenCalled()
|
|
118
|
+
expect(callback).toHaveBeenCalledTimes(1)
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
test('debounce respects order of calls', async () => {
|
|
122
|
+
const callback = jest.fn(() => {})
|
|
123
|
+
const debounced_function: (a: number) => void = debounce(callback)
|
|
124
|
+
debounced_function(0)
|
|
125
|
+
debounced_function(1)
|
|
126
|
+
|
|
127
|
+
await new Promise((r) => setTimeout(r, 50))
|
|
128
|
+
expect(callback).toHaveBeenCalledTimes(1)
|
|
129
|
+
expect(callback.mock.calls[0]).toStrictEqual([1])
|
|
130
|
+
})
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
describe('isEqual', () => {
|
|
134
|
+
test('different objects are not equal', () => {
|
|
135
|
+
expect(isEqual({ a: 1 }, { b: 1 })).toBe(false)
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
test('equal objects are equal', () => {
|
|
139
|
+
expect(isEqual({ a: 1 }, { a: 1 })).toBe(true)
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
test('more complex objects are equal', () => {
|
|
143
|
+
expect(isEqual({ a: 1, b: { c: 'asdf' } }, { a: 1, b: { c: 'asdf' } })).toBe(true)
|
|
144
|
+
})
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
describe('kebabCase', () => {
|
|
148
|
+
test('kebab-case string', () => {
|
|
149
|
+
expect(kebabCase('kebab-case')).toBe('kebab-case')
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
test('camelCase string', () => {
|
|
153
|
+
expect(kebabCase('camelCase')).toBe('camel-case')
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
test('string with initial uppercase', () => {
|
|
157
|
+
expect(kebabCase('UpperCase')).toBe('upper-case')
|
|
158
|
+
})
|
|
159
|
+
})
|
|
160
|
+
})
|
|
@@ -3,7 +3,7 @@ export function generateID(): string {
|
|
|
3
3
|
return Math.random().toString(36).substring(2, 10)
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
-
export function hasClassInTree(element: HTMLElement, className: string) {
|
|
6
|
+
export function hasClassInTree(element: HTMLElement, className: string): HTMLElement | null {
|
|
7
7
|
function hasClass(e: HTMLElement, c: string) {
|
|
8
8
|
// If the element has the class return element
|
|
9
9
|
if (c && e && e.classList && e.classList.contains(c)) {
|
|
@@ -51,20 +51,11 @@ export function debounce<T extends (...args: any[]) => void>(func: T, wait = 50,
|
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
function reverseDebounce<T extends (...args: any[]) => void>(func: T, timeout: number): T {
|
|
56
|
-
let timer: NodeJS.Timeout | null = null
|
|
57
|
-
return function (...args: any[]): void {
|
|
58
|
-
if (!timer) func(...args)
|
|
59
|
-
timer = setTimeout(() => (timer = null), timeout)
|
|
60
|
-
} as T
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export function isEqual(a: any, b: any) {
|
|
54
|
+
export function isEqual(a: any, b: any): boolean {
|
|
64
55
|
return JSON.stringify(a) === JSON.stringify(b)
|
|
65
56
|
}
|
|
66
57
|
|
|
67
|
-
export function kebabCase(str: string) {
|
|
58
|
+
export function kebabCase(str: string): string {
|
|
68
59
|
const result = str.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g, (match) => '-' + match.toLowerCase())
|
|
69
60
|
return str[0] === str[0].toUpperCase() ? result.substring(1) : result
|
|
70
61
|
}
|
|
@@ -3,19 +3,112 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
'use strict'
|
|
6
|
+
|
|
6
7
|
import { describe, expect, test } from '@jest/globals'
|
|
7
8
|
import SlimSelect from './'
|
|
8
9
|
import { OptionOptional } from './store'
|
|
9
10
|
import { Config } from './index'
|
|
10
11
|
|
|
11
12
|
describe('SlimSelect Module', () => {
|
|
12
|
-
|
|
13
|
+
let slim: SlimSelect
|
|
14
|
+
|
|
15
|
+
beforeEach(() => {
|
|
13
16
|
document.body.innerHTML = '<select id="test"></select>'
|
|
14
17
|
|
|
15
|
-
|
|
16
|
-
select: '#test'
|
|
18
|
+
slim = new SlimSelect({
|
|
19
|
+
select: '#test'
|
|
17
20
|
})
|
|
18
|
-
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
describe('constructor', () => {
|
|
24
|
+
test('missing select element throws error', () => {
|
|
25
|
+
const errorMock = jest.fn()
|
|
26
|
+
const slim = new SlimSelect({ select: '#invalid', events: { error: errorMock } })
|
|
27
|
+
|
|
28
|
+
expect(slim.select).toBeUndefined()
|
|
29
|
+
expect(slim.store).toBeUndefined()
|
|
30
|
+
expect(slim.render).toBeUndefined()
|
|
31
|
+
expect(errorMock).toHaveBeenCalled()
|
|
32
|
+
expect(errorMock.mock.calls[0][0].message).toBe('Could not find select element')
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
test('invalid element throws error', () => {
|
|
36
|
+
document.body.innerHTML = '<div id="invalid"></div>'
|
|
37
|
+
|
|
38
|
+
const errorMock = jest.fn()
|
|
39
|
+
const slim = new SlimSelect({ select: '#invalid', events: { error: errorMock } })
|
|
40
|
+
|
|
41
|
+
expect(slim.select).toBeUndefined()
|
|
42
|
+
expect(slim.store).toBeUndefined()
|
|
43
|
+
expect(slim.render).toBeUndefined()
|
|
44
|
+
expect(errorMock).toHaveBeenCalled()
|
|
45
|
+
expect(errorMock.mock.calls[0][0].message).toBe('Element isnt of type select')
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
test('valid minimal constructor with query string', () => {
|
|
49
|
+
document.body.innerHTML = '<select id="test"></select>'
|
|
50
|
+
|
|
51
|
+
const slimSelect = new SlimSelect({
|
|
52
|
+
select: '#test'
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
expect(slimSelect).toBeInstanceOf(SlimSelect)
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
test('valid minimal constructor with HTML element', () => {
|
|
59
|
+
document.body.innerHTML = '<select id="test"></select>'
|
|
60
|
+
|
|
61
|
+
const slimSelect = new SlimSelect({
|
|
62
|
+
select: document.getElementById('test') as Element
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
expect(slimSelect).toBeInstanceOf(SlimSelect)
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
test('disabled gets applied correctly', () => {
|
|
69
|
+
document.body.innerHTML = '<select id="test"></select>'
|
|
70
|
+
|
|
71
|
+
const slim = new SlimSelect({
|
|
72
|
+
select: document.getElementById('test') as Element,
|
|
73
|
+
settings: {
|
|
74
|
+
disabled: true
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
expect(slim.settings.disabled).toBe(true)
|
|
79
|
+
})
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
test('enable', () => {
|
|
83
|
+
slim.settings.disabled = true
|
|
84
|
+
|
|
85
|
+
const selectEnableMock = jest.fn()
|
|
86
|
+
const renderEnableMock = jest.fn()
|
|
87
|
+
|
|
88
|
+
slim.select.enable = selectEnableMock
|
|
89
|
+
slim.render.enable = renderEnableMock
|
|
90
|
+
|
|
91
|
+
slim.enable()
|
|
92
|
+
|
|
93
|
+
expect(slim.settings.disabled).toBe(false)
|
|
94
|
+
expect(selectEnableMock).toHaveBeenCalled()
|
|
95
|
+
expect(renderEnableMock).toHaveBeenCalled()
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
test('disable', () => {
|
|
99
|
+
slim.settings.disabled = false
|
|
100
|
+
|
|
101
|
+
const selectDisableMock = jest.fn()
|
|
102
|
+
const renderDisableMock = jest.fn()
|
|
103
|
+
|
|
104
|
+
slim.select.disable = selectDisableMock
|
|
105
|
+
slim.render.disable = renderDisableMock
|
|
106
|
+
|
|
107
|
+
slim.disable()
|
|
108
|
+
|
|
109
|
+
expect(slim.settings.disabled).toBe(true)
|
|
110
|
+
expect(selectDisableMock).toHaveBeenCalled()
|
|
111
|
+
expect(renderDisableMock).toHaveBeenCalled()
|
|
19
112
|
})
|
|
20
113
|
|
|
21
114
|
test('multiple - do not render deselect all with no selected options', () => {
|
|
@@ -30,25 +123,25 @@ describe('SlimSelect Module', () => {
|
|
|
30
123
|
{
|
|
31
124
|
id: '1',
|
|
32
125
|
value: '1',
|
|
33
|
-
text: 'One'
|
|
126
|
+
text: 'One'
|
|
34
127
|
},
|
|
35
128
|
{
|
|
36
129
|
id: '2',
|
|
37
130
|
value: '2',
|
|
38
|
-
text: 'Two'
|
|
131
|
+
text: 'Two'
|
|
39
132
|
},
|
|
40
133
|
{
|
|
41
134
|
id: '3',
|
|
42
135
|
value: '3',
|
|
43
|
-
text: 'Three'
|
|
44
|
-
}
|
|
136
|
+
text: 'Three'
|
|
137
|
+
}
|
|
45
138
|
]
|
|
46
139
|
const config: Config = {
|
|
47
140
|
select: '#test',
|
|
48
141
|
settings: {
|
|
49
|
-
allowDeselect: true
|
|
142
|
+
allowDeselect: true
|
|
50
143
|
},
|
|
51
|
-
data: options
|
|
144
|
+
data: options
|
|
52
145
|
}
|
|
53
146
|
|
|
54
147
|
let slimSelect = new SlimSelect(config)
|
|
@@ -69,26 +162,26 @@ describe('SlimSelect Module', () => {
|
|
|
69
162
|
id: '1',
|
|
70
163
|
value: '1',
|
|
71
164
|
text: 'One',
|
|
72
|
-
selected: true
|
|
165
|
+
selected: true
|
|
73
166
|
},
|
|
74
167
|
{
|
|
75
168
|
id: '2',
|
|
76
169
|
value: '2',
|
|
77
170
|
text: 'Two',
|
|
78
|
-
selected: true
|
|
171
|
+
selected: true
|
|
79
172
|
},
|
|
80
173
|
{
|
|
81
174
|
id: '3',
|
|
82
175
|
value: '3',
|
|
83
|
-
text: 'Three'
|
|
84
|
-
}
|
|
176
|
+
text: 'Three'
|
|
177
|
+
}
|
|
85
178
|
]
|
|
86
179
|
const config: Config = {
|
|
87
180
|
select: '#test',
|
|
88
181
|
settings: {
|
|
89
|
-
allowDeselect: true
|
|
182
|
+
allowDeselect: true
|
|
90
183
|
},
|
|
91
|
-
data: options
|
|
184
|
+
data: options
|
|
92
185
|
}
|
|
93
186
|
|
|
94
187
|
let slimSelect = new SlimSelect(config)
|
package/src/slim-select/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import CssClasses from './classes'
|
|
1
2
|
import { debounce, hasClassInTree, isEqual } from './helpers'
|
|
2
3
|
import Render from './render'
|
|
3
4
|
import Select from './select'
|
|
@@ -8,13 +9,16 @@ export interface Config {
|
|
|
8
9
|
select: string | Element
|
|
9
10
|
data?: DataArrayPartial
|
|
10
11
|
settings?: SettingsPartial
|
|
12
|
+
cssClasses?: Partial<CssClasses>
|
|
11
13
|
events?: Events
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
export interface Events {
|
|
15
17
|
search?: (searchValue: string, currentData: DataArray) => Promise<DataArrayPartial> | DataArrayPartial
|
|
16
18
|
searchFilter?: (option: Option, search: string) => boolean
|
|
17
|
-
addable?: (
|
|
19
|
+
addable?: (
|
|
20
|
+
value: string
|
|
21
|
+
) => Promise<OptionOptional | string> | OptionOptional | string | false | null | undefined | Error
|
|
18
22
|
beforeChange?: (newVal: Option[], oldVal: Option[]) => boolean | void
|
|
19
23
|
afterChange?: (newVal: Option[]) => void
|
|
20
24
|
beforeOpen?: () => void
|
|
@@ -29,6 +33,7 @@ export default class SlimSelect {
|
|
|
29
33
|
|
|
30
34
|
// Classes
|
|
31
35
|
public settings!: Settings
|
|
36
|
+
public cssClasses!: CssClasses
|
|
32
37
|
public select!: Select
|
|
33
38
|
public store!: Store
|
|
34
39
|
public render!: Render
|
|
@@ -45,7 +50,7 @@ export default class SlimSelect {
|
|
|
45
50
|
beforeOpen: undefined,
|
|
46
51
|
afterOpen: undefined,
|
|
47
52
|
beforeClose: undefined,
|
|
48
|
-
afterClose: undefined
|
|
53
|
+
afterClose: undefined
|
|
49
54
|
} as Events
|
|
50
55
|
|
|
51
56
|
constructor(config: Config) {
|
|
@@ -74,6 +79,9 @@ export default class SlimSelect {
|
|
|
74
79
|
// Set settings
|
|
75
80
|
this.settings = new Settings(config.settings)
|
|
76
81
|
|
|
82
|
+
// Set CSS classes
|
|
83
|
+
this.cssClasses = new CssClasses(config.cssClasses)
|
|
84
|
+
|
|
77
85
|
// Set events
|
|
78
86
|
const debounceEvents = ['afterChange', 'beforeOpen', 'afterOpen', 'beforeClose', 'afterClose']
|
|
79
87
|
for (const key in config.events) {
|
|
@@ -102,9 +110,9 @@ export default class SlimSelect {
|
|
|
102
110
|
this.select.hideUI() // Hide the original select element
|
|
103
111
|
|
|
104
112
|
// Add select listeners
|
|
105
|
-
this.select.onValueChange = (
|
|
113
|
+
this.select.onValueChange = (options: Option[]) => {
|
|
106
114
|
// Run set selected from the values given
|
|
107
|
-
this.setSelected(
|
|
115
|
+
this.setSelected(options.map((option) => option.id))
|
|
108
116
|
}
|
|
109
117
|
this.select.onClassChange = (classes: string[]) => {
|
|
110
118
|
// Update settings with new class
|
|
@@ -128,7 +136,7 @@ export default class SlimSelect {
|
|
|
128
136
|
// Set store class
|
|
129
137
|
this.store = new Store(
|
|
130
138
|
this.settings.isMultiple ? 'multiple' : 'single',
|
|
131
|
-
config.data ? config.data : this.select.getData()
|
|
139
|
+
config.data ? config.data : this.select.getData()
|
|
132
140
|
)
|
|
133
141
|
|
|
134
142
|
// If data is passed update the original select element
|
|
@@ -145,11 +153,11 @@ export default class SlimSelect {
|
|
|
145
153
|
addOption: this.addOption.bind(this),
|
|
146
154
|
search: this.search.bind(this),
|
|
147
155
|
beforeChange: this.events.beforeChange,
|
|
148
|
-
afterChange: this.events.afterChange
|
|
156
|
+
afterChange: this.events.afterChange
|
|
149
157
|
}
|
|
150
158
|
|
|
151
159
|
// Setup render class
|
|
152
|
-
this.render = new Render(this.settings, this.store, renderCallbacks)
|
|
160
|
+
this.render = new Render(this.settings, this.cssClasses, this.store, renderCallbacks)
|
|
153
161
|
this.render.renderValues()
|
|
154
162
|
this.render.renderOptions(this.store.getData())
|
|
155
163
|
|
|
@@ -245,15 +253,36 @@ export default class SlimSelect {
|
|
|
245
253
|
}
|
|
246
254
|
|
|
247
255
|
public getSelected(): string[] {
|
|
248
|
-
|
|
256
|
+
let options = this.store.getSelectedOptions()
|
|
257
|
+
if (this.settings.keepOrder) {
|
|
258
|
+
options = this.store.selectedOrderOptions(options)
|
|
259
|
+
}
|
|
260
|
+
return options.map((option) => option.value)
|
|
249
261
|
}
|
|
250
262
|
|
|
251
|
-
|
|
263
|
+
// Will take in a string or array of strings and set the selected by either the id or value
|
|
264
|
+
public setSelected(values: string | string[], runAfterChange = true): void {
|
|
252
265
|
// Get original selected values
|
|
253
266
|
const selected = this.store.getSelected()
|
|
267
|
+
const options = this.store.getDataOptions()
|
|
268
|
+
values = Array.isArray(values) ? values : [values]
|
|
269
|
+
const ids = []
|
|
270
|
+
|
|
271
|
+
// for back-compatibility support both, set by id and set by value
|
|
272
|
+
for (const value of values) {
|
|
273
|
+
if (options.find((option) => option.id == value)) {
|
|
274
|
+
ids.push(value)
|
|
275
|
+
continue
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// if option with given id is not found try to search by value
|
|
279
|
+
for (const option of options.filter((option) => option.value == value)) {
|
|
280
|
+
ids.push(option.id)
|
|
281
|
+
}
|
|
282
|
+
}
|
|
254
283
|
|
|
255
284
|
// Update the store
|
|
256
|
-
this.store.setSelectedBy('
|
|
285
|
+
this.store.setSelectedBy('id', ids)
|
|
257
286
|
const data = this.store.getData()
|
|
258
287
|
|
|
259
288
|
// Update the select element
|
|
@@ -315,7 +344,7 @@ export default class SlimSelect {
|
|
|
315
344
|
this.render.open()
|
|
316
345
|
|
|
317
346
|
// Focus on input field only if search is enabled
|
|
318
|
-
if (this.settings.showSearch) {
|
|
347
|
+
if (this.settings.showSearch && this.settings.focusSearch) {
|
|
319
348
|
this.render.searchFocus()
|
|
320
349
|
}
|
|
321
350
|
|
|
@@ -402,7 +431,7 @@ export default class SlimSelect {
|
|
|
402
431
|
if (!this.events.search) {
|
|
403
432
|
// If value is empty then render all options
|
|
404
433
|
this.render.renderOptions(
|
|
405
|
-
value === '' ? this.store.getData() : this.store.search(value, this.events.searchFilter!)
|
|
434
|
+
value === '' ? this.store.getData() : this.store.search(value, this.events.searchFilter!)
|
|
406
435
|
)
|
|
407
436
|
return
|
|
408
437
|
}
|