slim-select 3.1.0 → 3.1.1

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.
@@ -0,0 +1,498 @@
1
+ import { describe, expect, test, beforeEach, afterEach, vi } from 'vitest'
2
+ import { render, cleanup, act, waitFor } from '@testing-library/react'
3
+ import { useState, useEffect, useRef } from 'react'
4
+ import SlimSelect, { Option } from '../index'
5
+ import SlimSelectReact, { SlimSelectRef } from './react'
6
+
7
+ describe('SlimSelect React Component', () => {
8
+ let consoleInfoSpy: any
9
+ let consoleWarnSpy: any
10
+
11
+ beforeEach(() => {
12
+ // Mock console methods
13
+ consoleInfoSpy = vi.spyOn(console, 'info').mockImplementation(() => {})
14
+ consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
15
+ })
16
+
17
+ afterEach(() => {
18
+ cleanup()
19
+ // Restore console methods
20
+ consoleInfoSpy.mockRestore()
21
+ consoleWarnSpy.mockRestore()
22
+ })
23
+
24
+ describe('Basic Rendering', () => {
25
+ test('renders a select element', () => {
26
+ const { container } = render(<SlimSelectReact />)
27
+ const select = container.querySelector('select')
28
+ expect(select).toBeTruthy()
29
+ })
30
+
31
+ test('renders with single select by default', () => {
32
+ const { container } = render(<SlimSelectReact />)
33
+ const select = container.querySelector('select')
34
+ expect(select?.hasAttribute('multiple')).toBe(false)
35
+ })
36
+
37
+ test('renders with multiple attribute when multiple prop is true', () => {
38
+ const { container } = render(<SlimSelectReact multiple />)
39
+ const select = container.querySelector('select')
40
+ expect(select?.hasAttribute('multiple')).toBe(true)
41
+ })
42
+ })
43
+
44
+ describe('Value and onChange binding', () => {
45
+ test('accepts initial value for single select', async () => {
46
+ const TestComponent = () => {
47
+ const [value, setValue] = useState('2')
48
+ const ref = useRef<SlimSelectRef>(null)
49
+
50
+ return (
51
+ <SlimSelectReact
52
+ ref={ref}
53
+ value={value}
54
+ onChange={(val) => setValue(val as string)}
55
+ data={[
56
+ { value: '1', text: 'Option 1' },
57
+ { value: '2', text: 'Option 2' },
58
+ { value: '3', text: 'Option 3' }
59
+ ]}
60
+ />
61
+ )
62
+ }
63
+
64
+ const { container } = render(<TestComponent />)
65
+
66
+ await waitFor(
67
+ () => {
68
+ const select = container.querySelector('select')
69
+ const slimInstance = (select as any)?._slimSelect as SlimSelect
70
+ if (slimInstance) {
71
+ const selected = slimInstance.getSelected()
72
+ expect(selected[0]).toBe('2')
73
+ }
74
+ },
75
+ { timeout: 500 }
76
+ )
77
+ })
78
+
79
+ test('accepts initial value for multiple select', async () => {
80
+ const TestComponent = () => {
81
+ const [value, setValue] = useState(['2', '3'])
82
+ return (
83
+ <SlimSelectReact
84
+ value={value}
85
+ onChange={(val) => setValue(val as string[])}
86
+ multiple
87
+ data={[
88
+ { value: '1', text: 'Option 1' },
89
+ { value: '2', text: 'Option 2' },
90
+ { value: '3', text: 'Option 3' }
91
+ ]}
92
+ />
93
+ )
94
+ }
95
+
96
+ const { container } = render(<TestComponent />)
97
+
98
+ await waitFor(
99
+ () => {
100
+ const select = container.querySelector('select')
101
+ const slimInstance = (select as any)?._slimSelect as SlimSelect
102
+ if (slimInstance) {
103
+ const selected = slimInstance.getSelected()
104
+ expect(selected).toEqual(['2', '3'])
105
+ }
106
+ },
107
+ { timeout: 500 }
108
+ )
109
+ })
110
+
111
+ test('calls onChange when selection changes', async () => {
112
+ const onChangeMock = vi.fn()
113
+ const TestComponent = () => {
114
+ return (
115
+ <SlimSelectReact
116
+ value="1"
117
+ onChange={onChangeMock}
118
+ data={[
119
+ { value: '1', text: 'Option 1' },
120
+ { value: '2', text: 'Option 2' }
121
+ ]}
122
+ />
123
+ )
124
+ }
125
+
126
+ const { container } = render(<TestComponent />)
127
+
128
+ await waitFor(
129
+ async () => {
130
+ const select = container.querySelector('select')
131
+ const slimInstance = (select as any)?._slimSelect as SlimSelect
132
+ if (slimInstance) {
133
+ await act(async () => {
134
+ slimInstance.setSelected('2')
135
+ })
136
+ await waitFor(
137
+ () => {
138
+ expect(onChangeMock).toHaveBeenCalledWith('2')
139
+ },
140
+ { timeout: 500 }
141
+ )
142
+ }
143
+ },
144
+ { timeout: 500 }
145
+ )
146
+ })
147
+
148
+ test('updates selection when value prop changes', async () => {
149
+ const TestComponent = ({ initialValue }: { initialValue: string }) => {
150
+ const [value, setValue] = useState(initialValue)
151
+
152
+ useEffect(() => {
153
+ // Simulate parent updating value
154
+ const timer = setTimeout(() => {
155
+ act(() => {
156
+ setValue('2')
157
+ })
158
+ }, 100)
159
+ return () => clearTimeout(timer)
160
+ }, [])
161
+
162
+ return (
163
+ <SlimSelectReact
164
+ value={value}
165
+ onChange={(val) => setValue(val as string)}
166
+ data={[
167
+ { value: '1', text: 'Option 1' },
168
+ { value: '2', text: 'Option 2' }
169
+ ]}
170
+ />
171
+ )
172
+ }
173
+
174
+ const { container } = render(<TestComponent initialValue="1" />)
175
+
176
+ await waitFor(
177
+ () => {
178
+ const select = container.querySelector('select')
179
+ const slimInstance = (select as any)?._slimSelect as SlimSelect
180
+ if (slimInstance) {
181
+ const selected = slimInstance.getSelected()
182
+ expect(selected[0]).toBe('2')
183
+ }
184
+ },
185
+ { timeout: 500 }
186
+ )
187
+ })
188
+ })
189
+
190
+ describe('Data Prop', () => {
191
+ test('initializes with data prop', async () => {
192
+ const testData = [
193
+ { value: '1', text: 'Option 1' },
194
+ { value: '2', text: 'Option 2' },
195
+ { value: '3', text: 'Option 3' }
196
+ ]
197
+
198
+ const { container } = render(<SlimSelectReact data={testData} />)
199
+ await new Promise((resolve) => setTimeout(resolve, 100))
200
+
201
+ const select = container.querySelector('select')
202
+ const slimInstance = (select as any)?._slimSelect as SlimSelect
203
+ if (slimInstance) {
204
+ const data = slimInstance.getData()
205
+ expect(data).toHaveLength(3)
206
+ }
207
+ })
208
+
209
+ test('updates data when data prop changes', async () => {
210
+ const TestComponent = () => {
211
+ const [data, setData] = useState([
212
+ { value: '1', text: 'Option 1' },
213
+ { value: '2', text: 'Option 2' }
214
+ ])
215
+
216
+ useEffect(() => {
217
+ const timer = setTimeout(() => {
218
+ act(() => {
219
+ setData([
220
+ { value: '3', text: 'Option 3' },
221
+ { value: '4', text: 'Option 4' },
222
+ { value: '5', text: 'Option 5' }
223
+ ])
224
+ })
225
+ }, 100)
226
+ return () => clearTimeout(timer)
227
+ }, [])
228
+
229
+ return <SlimSelectReact data={data} />
230
+ }
231
+
232
+ const { container } = render(<TestComponent />)
233
+
234
+ await waitFor(
235
+ () => {
236
+ const select = container.querySelector('select')
237
+ const slimInstance = (select as any)?._slimSelect as SlimSelect
238
+ if (slimInstance) {
239
+ const data = slimInstance.getData()
240
+ expect(data).toHaveLength(3)
241
+ }
242
+ },
243
+ { timeout: 500 }
244
+ )
245
+ })
246
+ })
247
+
248
+ describe('Settings Prop', () => {
249
+ test('applies settings prop', async () => {
250
+ const { container } = render(
251
+ <SlimSelectReact
252
+ data={[{ value: '1', text: 'Option 1' }]}
253
+ settings={{
254
+ showSearch: false,
255
+ placeholderText: 'Custom Placeholder'
256
+ }}
257
+ />
258
+ )
259
+ await new Promise((resolve) => setTimeout(resolve, 100))
260
+
261
+ const select = container.querySelector('select')
262
+ const slimInstance = (select as any)?._slimSelect as SlimSelect
263
+ if (slimInstance) {
264
+ expect(slimInstance.settings.showSearch).toBe(false)
265
+ expect(slimInstance.settings.placeholderText).toBe('Custom Placeholder')
266
+ }
267
+ })
268
+ })
269
+
270
+ describe('Events Prop', () => {
271
+ test('calls afterChange event from events prop', async () => {
272
+ const afterChangeMock = vi.fn()
273
+
274
+ const TestComponent = () => {
275
+ return (
276
+ <SlimSelectReact
277
+ value="1"
278
+ data={[
279
+ { value: '1', text: 'Option 1' },
280
+ { value: '2', text: 'Option 2' }
281
+ ]}
282
+ events={{
283
+ afterChange: afterChangeMock
284
+ }}
285
+ />
286
+ )
287
+ }
288
+
289
+ const { container } = render(<TestComponent />)
290
+ await new Promise((resolve) => setTimeout(resolve, 100))
291
+
292
+ const select = container.querySelector('select')
293
+ const slimInstance = (select as any)?._slimSelect as SlimSelect
294
+ if (slimInstance) {
295
+ slimInstance.setSelected('2')
296
+ await new Promise((resolve) => setTimeout(resolve, 100))
297
+ expect(afterChangeMock).toHaveBeenCalled()
298
+ }
299
+ })
300
+
301
+ test('calls both custom afterChange and onChange', async () => {
302
+ const afterChangeMock = vi.fn()
303
+ const onChangeMock = vi.fn()
304
+
305
+ const TestComponent = () => {
306
+ return (
307
+ <SlimSelectReact
308
+ value="1"
309
+ onChange={onChangeMock}
310
+ data={[
311
+ { value: '1', text: 'Option 1' },
312
+ { value: '2', text: 'Option 2' }
313
+ ]}
314
+ events={{
315
+ afterChange: afterChangeMock
316
+ }}
317
+ />
318
+ )
319
+ }
320
+
321
+ const { container } = render(<TestComponent />)
322
+ await new Promise((resolve) => setTimeout(resolve, 100))
323
+
324
+ const select = container.querySelector('select')
325
+ const slimInstance = (select as any)?._slimSelect as SlimSelect
326
+ if (slimInstance) {
327
+ slimInstance.setSelected('2')
328
+ await new Promise((resolve) => setTimeout(resolve, 100))
329
+ expect(afterChangeMock).toHaveBeenCalled()
330
+ expect(onChangeMock).toHaveBeenCalledWith('2')
331
+ }
332
+ })
333
+ })
334
+
335
+ describe('Empty and Invalid Values', () => {
336
+ test('handles empty string as value for single select', async () => {
337
+ const TestComponent = () => {
338
+ const [value, setValue] = useState('')
339
+ return (
340
+ <SlimSelectReact
341
+ value={value}
342
+ onChange={(val) => setValue(val as string)}
343
+ data={[
344
+ { value: '1', text: 'Option 1' },
345
+ { value: '2', text: 'Option 2' }
346
+ ]}
347
+ />
348
+ )
349
+ }
350
+
351
+ const { container } = render(<TestComponent />)
352
+ await new Promise((resolve) => setTimeout(resolve, 100))
353
+
354
+ const select = container.querySelector('select')
355
+ const slimInstance = (select as any)?._slimSelect as SlimSelect
356
+ if (slimInstance) {
357
+ // Verify placeholder exists in data
358
+ const data = slimInstance.getData()
359
+ const hasPlaceholder = (data as Option[]).some((opt: any) => opt.placeholder)
360
+ expect(hasPlaceholder).toBe(true)
361
+
362
+ // CRITICAL: Verify what's actually selected - should be empty string (placeholder)
363
+ const selectedValues = slimInstance.getSelected()
364
+ expect(selectedValues).toEqual([''])
365
+
366
+ // Verify no valid option is selected
367
+ const hasValidOptionSelected = selectedValues.some((val) => val !== '' && ['1', '2'].includes(val))
368
+ expect(hasValidOptionSelected).toBe(false)
369
+ }
370
+ })
371
+
372
+ test('shows placeholder when value does not exist in options for single select', async () => {
373
+ const TestComponent = () => {
374
+ const [value, setValue] = useState('banana')
375
+ return (
376
+ <SlimSelectReact
377
+ value={value}
378
+ onChange={(val) => setValue(val as string)}
379
+ data={[
380
+ { value: '1', text: 'Option 1' },
381
+ { value: '2', text: 'Option 2' },
382
+ { value: '3', text: 'Option 3' }
383
+ ]}
384
+ />
385
+ )
386
+ }
387
+
388
+ const { container } = render(<TestComponent />)
389
+ await waitFor(
390
+ () => {
391
+ const select = container.querySelector('select')
392
+ const slimInstance = (select as any)?._slimSelect as SlimSelect
393
+ if (slimInstance) {
394
+ // Verify placeholder exists in data (with empty value, not 'banana')
395
+ const data = slimInstance.getData()
396
+ const hasPlaceholder = (data as Option[]).some((opt: any) => opt.placeholder)
397
+ expect(hasPlaceholder).toBe(true)
398
+
399
+ // CRITICAL: Check what's actually displayed in the SlimSelect UI
400
+ // SlimSelect renders a custom UI - check the .ss-single or .ss-placeholder element
401
+ const slimMain = container.querySelector('.ss-main') as HTMLElement
402
+ expect(slimMain).toBeDefined()
403
+
404
+ // Check what's in the .ss-values container
405
+ const ssValues = slimMain?.querySelector('.ss-values') as HTMLElement
406
+ expect(ssValues).toBeDefined()
407
+
408
+ // If placeholder is selected, it should show placeholder (no .ss-single element)
409
+ // If a real option is selected, it will show .ss-single with the option text
410
+ const singleValue = ssValues?.querySelector('.ss-single') as HTMLElement
411
+ const placeholderEl = ssValues?.querySelector('.ss-placeholder') as HTMLElement
412
+
413
+ // CRITICAL: If placeholder is correctly selected, we should NOT see .ss-single with "Option 1"
414
+ // Instead, we should either see placeholder OR empty (if placeholder text is empty)
415
+ if (singleValue) {
416
+ const displayedText = singleValue.textContent?.trim() || ''
417
+ // This should NOT be showing a real option
418
+ expect(displayedText).not.toBe('Option 1')
419
+ expect(displayedText).not.toBe('Option 2')
420
+ expect(displayedText).not.toBe('Option 3')
421
+
422
+ // If it's showing something, it might be the placeholder (empty text is OK)
423
+ // But we should verify the placeholder option is actually selected in the store
424
+ }
425
+
426
+ // Check the store to see what's actually selected
427
+ const selectedOptions = (slimInstance as any).store.getSelectedOptions()
428
+ const hasPlaceholderSelected = selectedOptions.some((opt: any) => opt.placeholder && opt.selected)
429
+ const hasValidOptionSelected = selectedOptions.some(
430
+ (opt: any) => opt.selected && !opt.placeholder && ['1', '2', '3'].includes(opt.value)
431
+ )
432
+
433
+ // The placeholder should be selected, not a valid option
434
+ expect(hasPlaceholderSelected).toBe(true)
435
+ expect(hasValidOptionSelected).toBe(false)
436
+ }
437
+ },
438
+ { timeout: 500 }
439
+ )
440
+ })
441
+
442
+ test('handles empty array as value for multiple select', async () => {
443
+ const TestComponent = () => {
444
+ const [value, setValue] = useState([] as string[])
445
+ return (
446
+ <SlimSelectReact
447
+ value={value}
448
+ onChange={(val) => setValue(val as string[])}
449
+ multiple
450
+ data={[
451
+ { value: '1', text: 'Option 1' },
452
+ { value: '2', text: 'Option 2' }
453
+ ]}
454
+ />
455
+ )
456
+ }
457
+
458
+ const { container } = render(<TestComponent />)
459
+ await new Promise((resolve) => setTimeout(resolve, 100))
460
+
461
+ // Should not throw errors
462
+ expect(container.querySelector('select')).toBeTruthy()
463
+ })
464
+
465
+ test('updates onChange for multiple select when invalid values are provided', async () => {
466
+ const onChangeMock = vi.fn()
467
+
468
+ const TestComponent = () => {
469
+ return (
470
+ <SlimSelectReact
471
+ value={['banana', 'apple']}
472
+ onChange={onChangeMock}
473
+ multiple
474
+ data={[
475
+ { value: '1', text: 'Option 1' },
476
+ { value: '2', text: 'Option 2' },
477
+ { value: '3', text: 'Option 3' }
478
+ ]}
479
+ />
480
+ )
481
+ }
482
+
483
+ const { container } = render(<TestComponent />)
484
+ await new Promise((resolve) => setTimeout(resolve, 100))
485
+
486
+ const select = container.querySelector('select')
487
+ const slimInstance = (select as any)?._slimSelect as SlimSelect
488
+ if (slimInstance) {
489
+ // When user manually selects valid options, onChange should update
490
+ slimInstance.setSelected(['1', '2'])
491
+ await new Promise((resolve) => setTimeout(resolve, 100))
492
+
493
+ // Verify onChange has been called with the valid values
494
+ expect(onChangeMock).toHaveBeenCalledWith(['1', '2'])
495
+ }
496
+ })
497
+ })
498
+ })
@@ -22,12 +22,72 @@ const SlimSelect = forwardRef<SlimSelectRef, SlimSelectProps>(
22
22
  const selectRef = useRef<HTMLSelectElement>(null)
23
23
  const slimSelectRef = useRef<SlimSelectCore | null>(null)
24
24
  const isInitialMount = useRef(true)
25
+ const currentValueRef = useRef<string | string[] | undefined>(value)
25
26
 
26
27
  // Expose SlimSelect instance to parent via ref
27
28
  useImperativeHandle(ref, () => ({
28
29
  slimSelect: slimSelectRef.current
29
30
  }))
30
31
 
32
+ // Helper to get clean value (similar to Vue's getCleanValue)
33
+ const getCleanValue = (val: string | string[] | undefined): string | string[] => {
34
+ // If its multiple and the value is a string, return an array with the string
35
+ if (typeof val === 'string') {
36
+ return multiple ? [val] : val
37
+ }
38
+
39
+ // If its not multiple and the value is an array, return the first item
40
+ if (Array.isArray(val)) {
41
+ return multiple ? val : val[0]
42
+ }
43
+
44
+ return multiple ? [] : ''
45
+ }
46
+
47
+ // Helper to sync value to SlimSelect (similar to Vue's syncModelValueToSlimSelect)
48
+ const syncValueToSlimSelect = (val: string | string[] | undefined, runAfterChange: boolean = false) => {
49
+ if (!slimSelectRef.current) return
50
+
51
+ // Only sync if value is explicitly set (not undefined)
52
+ // This prevents adding placeholders when value is not provided
53
+ if (val === undefined) {
54
+ return
55
+ }
56
+
57
+ const cleanValue = getCleanValue(val)
58
+ const data = slimSelectRef.current.getData()
59
+ // Extract options from data (flatten optgroups if any)
60
+ const options = data.flatMap((item: Option | Optgroup) => ('label' in item ? item.options : [item])) as Option[]
61
+
62
+ // Check if the value exists in options
63
+ const valueExists = Array.isArray(cleanValue)
64
+ ? cleanValue.length > 0 && cleanValue.every((val) => options.some((opt) => opt.value === val))
65
+ : cleanValue !== '' && options.some((opt) => opt.value === cleanValue)
66
+
67
+ // If value doesn't exist in options, add a placeholder option
68
+ if (!valueExists) {
69
+ // If its not multiple, add a placeholder option
70
+ if (!Array.isArray(cleanValue)) {
71
+ // For single select, check if placeholder already exists
72
+ const hasPlaceholder = options.some((opt) => opt.placeholder)
73
+ if (!hasPlaceholder) {
74
+ // Get current data and prepend placeholder option
75
+ const currentData = slimSelectRef.current.getData()
76
+ const placeholderOption: Partial<Option> = {
77
+ value: '',
78
+ text: '',
79
+ placeholder: true
80
+ }
81
+ slimSelectRef.current.setData([placeholderOption].concat(currentData))
82
+ }
83
+ }
84
+ }
85
+
86
+ // Set the selected value (will select placeholder if it was just added)
87
+ // Match Vue component exactly - call setSelected with cleanValue directly
88
+ slimSelectRef.current.setSelected(cleanValue, runAfterChange)
89
+ }
90
+
31
91
  // Initialize SlimSelect
32
92
  useEffect(() => {
33
93
  if (!selectRef.current) return
@@ -53,10 +113,41 @@ const SlimSelect = forwardRef<SlimSelectRef, SlimSelectProps>(
53
113
  config.events = {
54
114
  ...events,
55
115
  afterChange: (newVal) => {
56
- const newValue = multiple ? newVal.map((option) => option.value) : (newVal[0]?.value ?? '')
116
+ if (!slimSelectRef.current) return
57
117
 
58
- if (onChange) {
118
+ const newValue = multiple ? newVal.map((option) => option.value) : (newVal[0]?.value ?? '')
119
+ const slimData = slimSelectRef.current.getData()
120
+ const options = slimData.flatMap((item: Option | Optgroup) =>
121
+ 'label' in item ? item.options : [item]
122
+ ) as Option[]
123
+
124
+ // Check if the current value exists in options
125
+ const currentValue = currentValueRef.current
126
+ const currentValueExists =
127
+ currentValue === undefined
128
+ ? false
129
+ : Array.isArray(currentValue)
130
+ ? currentValue.length > 0 && currentValue.every((val) => options.some((opt) => opt.value === val))
131
+ : currentValue !== '' && options.some((opt) => opt.value === currentValue)
132
+
133
+ // Check if the new value is valid (exists in options)
134
+ const newValueIsValid = Array.isArray(newValue)
135
+ ? newValue.length > 0 && newValue.every((val) => options.some((opt) => opt.value === val))
136
+ : newValue !== '' && options.some((opt) => opt.value === newValue)
137
+
138
+ // Check if value actually changed (properly compare arrays)
139
+ const valueChanged =
140
+ Array.isArray(newValue) && Array.isArray(currentValue)
141
+ ? JSON.stringify(newValue.sort()) !== JSON.stringify(currentValue.sort())
142
+ : currentValue !== newValue
143
+
144
+ // Only call onChange if:
145
+ // 1. The value actually changed, AND
146
+ // 2. Either the current value exists in options, OR we're setting to a valid non-empty value
147
+ // This prevents clearing invalid values when we show placeholder
148
+ if (onChange && valueChanged && (currentValueExists || newValueIsValid)) {
59
149
  onChange(newValue)
150
+ currentValueRef.current = newValue
60
151
  }
61
152
 
62
153
  if (ogAfterChange) {
@@ -67,9 +158,9 @@ const SlimSelect = forwardRef<SlimSelectRef, SlimSelectProps>(
67
158
 
68
159
  slimSelectRef.current = new SlimSelectCore(config)
69
160
 
70
- // Set initial value if provided
161
+ // Sync initial value if provided
71
162
  if (value !== undefined) {
72
- slimSelectRef.current.setSelected(value, false)
163
+ syncValueToSlimSelect(value, false)
73
164
  }
74
165
 
75
166
  return () => {
@@ -84,11 +175,13 @@ const SlimSelect = forwardRef<SlimSelectRef, SlimSelectProps>(
84
175
  useEffect(() => {
85
176
  if (isInitialMount.current) {
86
177
  isInitialMount.current = false
178
+ currentValueRef.current = value
87
179
  return
88
180
  }
89
181
 
90
182
  if (slimSelectRef.current && value !== undefined) {
91
- slimSelectRef.current.setSelected(value, false)
183
+ currentValueRef.current = value
184
+ syncValueToSlimSelect(value, false)
92
185
  }
93
186
  }, [value])
94
187
 
@@ -96,6 +189,10 @@ const SlimSelect = forwardRef<SlimSelectRef, SlimSelectProps>(
96
189
  useEffect(() => {
97
190
  if (slimSelectRef.current && data && !isInitialMount.current) {
98
191
  slimSelectRef.current.setData(data)
192
+ // Re-sync value after data changes
193
+ if (value !== undefined) {
194
+ syncValueToSlimSelect(value, false)
195
+ }
99
196
  }
100
197
  }, [data])
101
198