slim-select 2.13.1 → 3.0.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.
Files changed (60) hide show
  1. package/README.md +185 -44
  2. package/dist/index.d.ts +304 -52
  3. package/dist/react/index.d.ts +304 -0
  4. package/dist/react/index.js +1549 -0
  5. package/dist/react/index.umd.js +22 -0
  6. package/dist/slimselect.cjs.js +2 -2030
  7. package/dist/slimselect.cjs.js.map +1 -0
  8. package/dist/slimselect.css +1 -1
  9. package/dist/slimselect.css.map +1 -1
  10. package/dist/slimselect.es.js +1225 -2012
  11. package/dist/slimselect.es.js.map +1 -0
  12. package/dist/slimselect.iife.js +2 -0
  13. package/dist/slimselect.iife.js.map +1 -0
  14. package/dist/slimselect.js +2 -2036
  15. package/dist/slimselect.js.map +1 -0
  16. package/dist/vue/index.d.ts +304 -0
  17. package/dist/vue/index.js +1341 -0
  18. package/dist/vue/index.umd.js +1 -0
  19. package/index.html +1 -0
  20. package/package.json +63 -40
  21. package/release.js +0 -7
  22. package/src/slim-select/accessibility.test.ts +782 -0
  23. package/src/slim-select/classes.test.ts +7 -6
  24. package/src/slim-select/classes.ts +8 -6
  25. package/src/slim-select/helpers.test.ts +10 -8
  26. package/src/slim-select/index.test.ts +509 -14
  27. package/src/slim-select/index.ts +58 -31
  28. package/src/slim-select/react/index.tsx +9 -0
  29. package/src/slim-select/react/react.tsx +112 -0
  30. package/src/slim-select/render.test.ts +479 -119
  31. package/src/slim-select/render.ts +213 -91
  32. package/src/slim-select/select.test.ts +28 -10
  33. package/src/slim-select/select.ts +35 -12
  34. package/src/slim-select/settings.test.ts +19 -8
  35. package/src/slim-select/settings.ts +2 -4
  36. package/src/slim-select/slimselect.scss +30 -15
  37. package/src/slim-select/store.test.ts +13 -16
  38. package/src/slim-select/store.ts +97 -86
  39. package/src/slim-select/vue/index.ts +9 -0
  40. package/src/slim-select/vue/vue.test.ts +832 -0
  41. package/src/slim-select/{vue.vue → vue/vue.vue} +45 -23
  42. package/tsconfig.json +6 -4
  43. package/{vite.config.mts → vite.config.docs.mts} +10 -0
  44. package/vite.config.lib.mts +48 -0
  45. package/vite.config.react.mts +40 -0
  46. package/vite.config.vue.mts +39 -0
  47. package/vitest.config.ts +29 -0
  48. package/dist/classes.d.ts +0 -43
  49. package/dist/helpers.d.ts +0 -5
  50. package/dist/render.d.ts +0 -81
  51. package/dist/select.d.ts +0 -30
  52. package/dist/settings.d.ts +0 -35
  53. package/dist/slimselect.global.js +0 -2033
  54. package/dist/slimselect.min.js +0 -1
  55. package/dist/slimselect.umd.js +0 -2036
  56. package/dist/slimselect.umd.min.js +0 -1
  57. package/dist/store.d.ts +0 -84
  58. package/jest.config.js +0 -14
  59. package/src/slim-select/rollup.config.mjs +0 -127
  60. package/src/slim-select/tsconfig.json +0 -14
@@ -1,64 +1,7 @@
1
1
  import { generateID } from './helpers'
2
2
 
3
- export type DataArray = DataObject[]
4
- export type DataObject = Optgroup | Option
5
-
6
- export type DataArrayPartial = DataObjectPartial[]
7
- export type DataObjectPartial = OptgroupOptional | OptionOptional
8
-
9
3
  type selectType = 'single' | 'multiple'
10
4
 
11
- export interface OptgroupOptional {
12
- id?: string
13
- label: string // Required
14
- selectAll?: boolean
15
- selectAllText?: string
16
- closable?: 'off' | 'open' | 'close'
17
- options?: OptionOptional[]
18
- }
19
-
20
- export class Optgroup {
21
- public id: string
22
- public label: string
23
- public selectAll: boolean
24
- public selectAllText: string
25
- public closable: 'off' | 'open' | 'close'
26
- public options: Option[]
27
-
28
- constructor(optgroup: OptgroupOptional) {
29
- this.id = !optgroup.id || optgroup.id === '' ? generateID() : optgroup.id
30
- this.label = optgroup.label || ''
31
- this.selectAll = optgroup.selectAll === undefined ? false : optgroup.selectAll
32
- this.selectAllText = optgroup.selectAllText || 'Select All'
33
- this.closable = optgroup.closable || 'off'
34
-
35
- // If options exist, loop through options and create new option class
36
- // and set the options to the optgroup options field
37
- this.options = []
38
- if (optgroup.options) {
39
- for (const o of optgroup.options) {
40
- this.options.push(new Option(o))
41
- }
42
- }
43
- }
44
- }
45
-
46
- export interface OptionOptional {
47
- id?: string
48
- value?: string
49
- text: string // Required
50
- html?: string
51
- selected?: boolean
52
- defaultSelected?: boolean
53
- display?: boolean
54
- disabled?: boolean
55
- mandatory?: boolean
56
- placeholder?: boolean
57
- class?: string
58
- style?: string
59
- data?: { [key: string]: string }
60
- }
61
-
62
5
  export class Option {
63
6
  id: string
64
7
  value: string
@@ -74,9 +17,9 @@ export class Option {
74
17
  data: { [key: string]: string }
75
18
  mandatory: boolean
76
19
 
77
- constructor(option: OptionOptional) {
20
+ constructor(option: Partial<Option>) {
78
21
  this.id = !option.id || option.id === '' ? generateID() : option.id
79
- this.value = option.value === undefined ? option.text : option.value
22
+ this.value = option.value === undefined ? option.text || '' : option.value || ''
80
23
  this.text = option.text || ''
81
24
  this.html = option.html || ''
82
25
  this.defaultSelected = option.defaultSelected !== undefined ? option.defaultSelected : false
@@ -90,27 +33,54 @@ export class Option {
90
33
  this.data = option.data || {}
91
34
  }
92
35
  }
36
+ export class Optgroup {
37
+ public id: string
38
+ public label: string
39
+ public selectAll: boolean
40
+ public selectAllText: string
41
+ public closable: 'off' | 'open' | 'close'
42
+ public options: Partial<Option>[]
43
+
44
+ constructor(optgroup: Partial<Optgroup>) {
45
+ this.id = !optgroup.id || optgroup.id === '' ? generateID() : optgroup.id
46
+ this.label = optgroup.label || ''
47
+ this.selectAll = optgroup.selectAll === undefined ? false : optgroup.selectAll
48
+ this.selectAllText = optgroup.selectAllText || 'Select All'
49
+ this.closable = optgroup.closable || 'off'
50
+
51
+ // If options exist, loop through options and create new option class
52
+ // and set the options to the optgroup options field
53
+ this.options = []
54
+ if (optgroup.options) {
55
+ for (const o of optgroup.options) {
56
+ this.options.push(new Option(o))
57
+ }
58
+ }
59
+ }
60
+ }
93
61
 
94
62
  export default class Store {
95
63
  private selectType: selectType = 'single'
96
64
 
97
65
  // Main data set, never null
98
- private data: DataArray = []
66
+ private data: (Option | Optgroup)[] = []
99
67
  private selectedOrder: string[] = []
100
68
 
101
- constructor(type: selectType, data: DataArrayPartial) {
69
+ constructor(type: selectType, data: (Partial<Option> | Partial<Optgroup>)[]) {
102
70
  this.selectType = type
103
71
  this.setData(data)
104
72
  }
105
73
 
106
74
  // Validate DataArrayPartial
107
- public validateDataArray(data: DataArray | DataArrayPartial): Error | null {
75
+ public validateDataArray(data: (Partial<Option> | Partial<Optgroup>)[]): Error | null {
108
76
  if (!Array.isArray(data)) {
109
77
  return new Error('Data must be an array')
110
78
  }
111
79
 
112
80
  // Loop through each data object
113
81
  for (let dataObj of data) {
82
+ if (!dataObj) continue
83
+
114
84
  // Optgroup
115
85
  if (dataObj instanceof Optgroup || 'label' in dataObj) {
116
86
  if (!('label' in dataObj)) {
@@ -139,7 +109,7 @@ export default class Store {
139
109
  }
140
110
 
141
111
  // Validate Option
142
- public validateOption(option: Option | OptionOptional): Error | null {
112
+ public validateOption(option: Partial<Option>): Error | null {
143
113
  if (!('text' in option)) {
144
114
  return new Error('Option must have a text')
145
115
  }
@@ -147,34 +117,73 @@ export default class Store {
147
117
  return null
148
118
  }
149
119
 
150
- public partialToFullData(data: DataArrayPartial): DataArray {
151
- let dataFinal: DataArray = []
152
- data.forEach((dataObj: DataObject | DataObjectPartial) => {
120
+ public partialToFullData(data: (Partial<Option> | Partial<Optgroup>)[]): (Option | Optgroup)[] {
121
+ let dataFinal: (Option | Optgroup)[] = []
122
+ data.forEach((dataObj) => {
123
+ if (!dataObj) return
124
+
153
125
  // Optgroup
154
126
  if (dataObj instanceof Optgroup || 'label' in dataObj) {
155
127
  let optOptions: Option[] = []
156
128
  if ('options' in dataObj && dataObj.options) {
157
- dataObj.options.forEach((option: Option | OptionOptional) => {
129
+ dataObj.options.forEach((option: Partial<Option>) => {
158
130
  optOptions.push(new Option(option))
159
131
  })
160
132
  }
161
133
 
162
134
  if (optOptions.length > 0) {
163
- dataFinal.push(new Optgroup(dataObj))
135
+ dataFinal.push(new Optgroup(dataObj as Partial<Optgroup>))
164
136
  }
165
137
  }
166
138
 
167
139
  // Option
168
140
  if (dataObj instanceof Option || 'text' in dataObj) {
169
- dataFinal.push(new Option(dataObj))
141
+ dataFinal.push(new Option(dataObj as Partial<Option>))
170
142
  }
171
143
  })
172
144
 
173
145
  return dataFinal
174
146
  }
175
147
 
176
- public setData(data: DataArray | DataArrayPartial) {
177
- this.data = this.partialToFullData(data)
148
+ public setData(data: (Partial<Option> | Partial<Optgroup>)[], preserveSelected: boolean = false) {
149
+ // Convert new data to full data array
150
+ const newData = this.partialToFullData(data)
151
+
152
+ if (preserveSelected) {
153
+ // Get currently selected options before updating data
154
+ const selectedOptions = this.getSelectedOptions()
155
+
156
+ // Check which selected options are missing from new data
157
+ const missingSelected: (Option | Optgroup)[] = []
158
+ selectedOptions.forEach((selectedOption) => {
159
+ let found = false
160
+
161
+ // Check if this selected option exists in new data
162
+ for (const newItem of newData) {
163
+ if (newItem instanceof Option && newItem.id === selectedOption.id) {
164
+ found = true
165
+ break
166
+ }
167
+ if (newItem instanceof Optgroup) {
168
+ for (const opt of newItem.options) {
169
+ if (opt.id === selectedOption.id) {
170
+ found = true
171
+ break
172
+ }
173
+ }
174
+ }
175
+ }
176
+
177
+ if (!found) {
178
+ missingSelected.push(selectedOption)
179
+ }
180
+ })
181
+
182
+ // Add missing selected options to the beginning of the data
183
+ this.data = [...missingSelected, ...newData]
184
+ } else {
185
+ this.data = newData
186
+ }
178
187
 
179
188
  // Run this.data through setSelected by value
180
189
  // to set the selected property and clean any wrong selected
@@ -184,8 +193,8 @@ export default class Store {
184
193
  }
185
194
 
186
195
  // Get data will return all the data
187
- public getData(): DataArray {
188
- return this.filter(null, true)
196
+ public getData(): Option[] | Optgroup[] {
197
+ return this.filter(null, true) as Option[] | Optgroup[]
189
198
  }
190
199
 
191
200
  // Get data options will return the data as a
@@ -194,9 +203,9 @@ export default class Store {
194
203
  return this.filter(null, false) as Option[]
195
204
  }
196
205
 
197
- public addOption(option: OptionOptional, addToStart: boolean = false) {
206
+ public addOption(option: Partial<Option>, addToStart: boolean = false) {
198
207
  if (addToStart) {
199
- let data = [new Option(option)] as DataArray
208
+ let data = [new Option(option)] as (Option | Optgroup)[]
200
209
  this.setData(data.concat(this.getData()))
201
210
  } else {
202
211
  this.setData(this.getData().concat(new Option(option)))
@@ -207,19 +216,20 @@ export default class Store {
207
216
  // each option and set the selected property to true
208
217
  // but also clean selected by determining selectType
209
218
  public setSelectedBy(selectedType: 'id' | 'value', selectedValues: string[]) {
210
- let firstOption: Option | null = null
219
+ let firstOption: Partial<Option> | null = null
211
220
  let hasSelected = false
212
- const selectedObjects: Option[] = []
221
+ const selectedObjects: Partial<Option>[] = []
213
222
 
214
223
  for (let dataObj of this.data) {
215
224
  // Optgroup
216
225
  if (dataObj instanceof Optgroup) {
217
- for (let option of dataObj.options) {
226
+ for (let option of dataObj.options as Partial<Option>[]) {
218
227
  if (!firstOption) {
219
228
  firstOption = option
220
229
  }
221
230
 
222
- option.selected = hasSelected ? false : selectedValues.includes(option[selectedType])
231
+ let optionValue = option[selectedType] || ''
232
+ option.selected = hasSelected ? false : selectedValues.includes(optionValue)
223
233
 
224
234
  // If the option is selected, set hasSelected to true
225
235
  // for single based selects
@@ -309,7 +319,7 @@ export default class Store {
309
319
  let option: Option | null = null
310
320
  for (let dataObj of this.data) {
311
321
  if (dataObj instanceof Optgroup) {
312
- option = dataObj.options[0]
322
+ option = dataObj.options[0] as Option
313
323
  } else if (dataObj instanceof Option) {
314
324
  option = dataObj
315
325
  }
@@ -322,7 +332,7 @@ export default class Store {
322
332
  }
323
333
 
324
334
  // Take in search string and return filtered list of values
325
- public search(search: string, searchFilter: (opt: Option, search: string) => boolean): DataArray {
335
+ public search(search: string, searchFilter: (opt: Option, search: string) => boolean): (Option | Optgroup)[] {
326
336
  search = search.trim()
327
337
 
328
338
  // If search is empty, return all data
@@ -338,14 +348,15 @@ export default class Store {
338
348
 
339
349
  // Filter takes in a function that will be used to filter the data
340
350
  // This will also keep optgroups of sub options meet the filter requirements
341
- public filter(filter: { (opt: Option): boolean } | null, includeOptgroup: boolean): DataArray {
342
- const dataSearch: DataArray = []
343
- this.data.forEach((dataObj: DataObject) => {
351
+ public filter(filter: { (opt: Option): boolean } | null, includeOptgroup: boolean): (Option | Optgroup)[] {
352
+ const dataSearch: (Option | Optgroup)[] = []
353
+ this.data.forEach((dataObj: Option | Optgroup) => {
344
354
  // Optgroup
345
355
  if (dataObj instanceof Optgroup) {
346
356
  let optOptions: Option[] = []
347
- dataObj.options.forEach((option: Option) => {
348
- if (!filter || filter(option)) {
357
+ let options = dataObj.options as Option[]
358
+ options.forEach((option: Option) => {
359
+ if (!filter || filter(option as Option)) {
349
360
  // If you dont want to include optgroups
350
361
  // just push to the dataSearch array
351
362
  if (!includeOptgroup) {
@@ -0,0 +1,9 @@
1
+ import SlimSelect from './vue.vue'
2
+
3
+ export default SlimSelect
4
+
5
+ // Re-export classes
6
+ export { Settings, Option, Optgroup } from '../index'
7
+
8
+ // Re-export types
9
+ export type { Config, Events } from '../index'