slim-select 2.8.2 → 2.9.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 (69) hide show
  1. package/.prettierignore +1 -0
  2. package/.prettierrc +4 -3
  3. package/README.md +5 -2
  4. package/dist/classes.d.ts +43 -0
  5. package/dist/helpers.d.ts +1 -1
  6. package/dist/index.d.ts +5 -2
  7. package/dist/render.d.ts +4 -44
  8. package/dist/select.d.ts +4 -2
  9. package/dist/settings.d.ts +2 -1
  10. package/dist/slimselect.cjs.js +248 -120
  11. package/dist/slimselect.css +1 -1
  12. package/dist/slimselect.css.map +1 -1
  13. package/dist/slimselect.es.js +248 -120
  14. package/dist/slimselect.global.js +248 -120
  15. package/dist/slimselect.js +248 -120
  16. package/dist/slimselect.min.js +1 -1
  17. package/dist/slimselect.umd.js +248 -120
  18. package/dist/slimselect.umd.min.js +1 -1
  19. package/dist/store.d.ts +4 -2
  20. package/index.html +1 -4
  21. package/jest.config.js +6 -0
  22. package/package.json +31 -40
  23. package/src/slim-select/classes.test.ts +72 -0
  24. package/src/slim-select/classes.ts +109 -0
  25. package/src/slim-select/helpers.test.ts +160 -0
  26. package/src/slim-select/helpers.ts +3 -12
  27. package/src/slim-select/index.test.ts +109 -16
  28. package/src/slim-select/index.ts +41 -12
  29. package/src/slim-select/render.test.ts +1169 -18
  30. package/src/slim-select/render.ts +78 -97
  31. package/src/slim-select/rollup.config.mjs +28 -28
  32. package/src/slim-select/select.test.ts +306 -156
  33. package/src/slim-select/select.ts +70 -21
  34. package/src/slim-select/settings.test.ts +272 -0
  35. package/src/slim-select/settings.ts +5 -1
  36. package/src/slim-select/slimselect.scss +7 -3
  37. package/src/slim-select/store.test.ts +986 -235
  38. package/src/slim-select/store.ts +70 -28
  39. package/src/{vue/slimselect.vue → slim-select/vue.vue} +19 -17
  40. package/tsconfig.json +2 -3
  41. package/{vite.config.ts → vite.config.mts} +11 -4
  42. package/src/react/.eslintignore +0 -2
  43. package/src/react/.eslintrc.cjs +0 -24
  44. package/src/react/index.html +0 -14
  45. package/src/react/jestconfig.json +0 -11
  46. package/src/react/package.json +0 -32
  47. package/src/react/src/frameworkpage.tsx +0 -133
  48. package/src/react/src/index.ts +0 -3
  49. package/src/react/src/slimselect.tsx +0 -148
  50. package/src/react/tests/slimselect.test.tsx +0 -52
  51. package/src/react/tsconfig.json +0 -37
  52. package/src/react/tsconfig.node.json +0 -10
  53. package/src/react/vite.config.ts +0 -55
  54. package/src/vue/README.md +0 -48
  55. package/src/vue/dist/slim-select/helpers.d.ts +0 -5
  56. package/src/vue/dist/slim-select/index.d.ts +0 -46
  57. package/src/vue/dist/slim-select/render.d.ts +0 -120
  58. package/src/vue/dist/slim-select/select.d.ts +0 -28
  59. package/src/vue/dist/slim-select/settings.d.ts +0 -34
  60. package/src/vue/dist/slim-select/store.d.ts +0 -80
  61. package/src/vue/dist/slimselectvue.es.js +0 -1978
  62. package/src/vue/dist/slimselectvue.global.js +0 -1981
  63. package/src/vue/dist/slimselectvue.ssr.js +0 -1980
  64. package/src/vue/dist/vue/hello.d.ts +0 -2
  65. package/src/vue/dist/vue/slimselect.vue.d.ts +0 -326
  66. package/src/vue/hello.ts +0 -5
  67. package/src/vue/package.json +0 -28
  68. package/src/vue/rollup.config.mjs +0 -44
  69. package/src/vue/tsconfig.json +0 -14
@@ -93,6 +93,7 @@ export default class Store {
93
93
 
94
94
  // Main data set, never null
95
95
  private data: DataArray = []
96
+ private selectedOrder: string[] = []
96
97
 
97
98
  constructor(type: selectType, data: DataArrayPartial) {
98
99
  this.selectType = type
@@ -115,11 +116,17 @@ export default class Store {
115
116
 
116
117
  if ('options' in dataObj && dataObj.options) {
117
118
  for (let option of dataObj.options) {
118
- return this.validateOption(option)
119
+ const validationError = this.validateOption(option)
120
+ if (validationError) {
121
+ return validationError
122
+ }
119
123
  }
120
124
  }
121
125
  } else if (dataObj instanceof Option || 'text' in dataObj) {
122
- return this.validateOption(dataObj)
126
+ const validationError = this.validateOption(dataObj)
127
+ if (validationError) {
128
+ return validationError
129
+ }
123
130
  } else {
124
131
  return new Error('Data object must be a valid optgroup or option')
125
132
  }
@@ -169,7 +176,7 @@ export default class Store {
169
176
  // Run this.data through setSelected by value
170
177
  // to set the selected property and clean any wrong selected
171
178
  if (this.selectType === 'single') {
172
- this.setSelectedBy('value', this.getSelected())
179
+ this.setSelectedBy('id', this.getSelected())
173
180
  }
174
181
  }
175
182
 
@@ -184,8 +191,13 @@ export default class Store {
184
191
  return this.filter(null, false) as Option[]
185
192
  }
186
193
 
187
- public addOption(option: OptionOptional) {
188
- this.setData(this.getData().concat(new Option(option)))
194
+ public addOption(option: OptionOptional, addToStart: boolean = false) {
195
+ if (addToStart) {
196
+ let data = [new Option(option)] as DataArray
197
+ this.setData(data.concat(this.getData()))
198
+ } else {
199
+ this.setData(this.getData().concat(new Option(option)))
200
+ }
189
201
  }
190
202
 
191
203
  // Pass in an array of id that will loop through
@@ -194,6 +206,7 @@ export default class Store {
194
206
  public setSelectedBy(selectedType: 'id' | 'value', selectedValues: string[]) {
195
207
  let firstOption: Option | null = null
196
208
  let hasSelected = false
209
+ const selectedObjects: Option[] = []
197
210
 
198
211
  for (let dataObj of this.data) {
199
212
  // Optgroup
@@ -207,8 +220,12 @@ export default class Store {
207
220
 
208
221
  // If the option is selected, set hasSelected to true
209
222
  // for single based selects
210
- if (option.selected && this.selectType === 'single') {
211
- hasSelected = true
223
+ if (option.selected) {
224
+ selectedObjects.push(option)
225
+
226
+ if (this.selectType === 'single') {
227
+ hasSelected = true
228
+ }
212
229
  }
213
230
  }
214
231
  }
@@ -223,8 +240,12 @@ export default class Store {
223
240
 
224
241
  // If the option is selected, set hasSelected to true
225
242
  // for single based selects
226
- if (dataObj.selected && this.selectType === 'single') {
227
- hasSelected = true
243
+ if (dataObj.selected) {
244
+ selectedObjects.push(dataObj)
245
+
246
+ if (this.selectType === 'single') {
247
+ hasSelected = true
248
+ }
228
249
  }
229
250
  }
230
251
  }
@@ -232,19 +253,23 @@ export default class Store {
232
253
  // If no options are selected, select the first option
233
254
  if (this.selectType === 'single' && firstOption && !hasSelected) {
234
255
  firstOption.selected = true
256
+ selectedObjects.push(firstOption)
235
257
  }
258
+
259
+ // Put together a list of selected ids in the order of the selected values
260
+ const selectedIds = selectedValues.map((value) => {
261
+ return selectedObjects.find((option) => option[selectedType] === value)?.id || ''
262
+ })
263
+
264
+ this.selectedOrder = selectedIds
236
265
  }
237
266
 
238
267
  public getSelected(): string[] {
239
- let selectedOptions = this.getSelectedOptions()
240
- let selectedValues: string[] = []
241
-
242
- // Loop through each option and get the value
243
- selectedOptions.forEach((option: Option) => {
244
- selectedValues.push(option.value)
245
- })
268
+ return this.getSelectedOptions().map((option) => option.id)
269
+ }
246
270
 
247
- return selectedValues
271
+ public getSelectedValues(): string[] {
272
+ return this.getSelectedOptions().map((option) => option.value)
248
273
  }
249
274
 
250
275
  public getSelectedOptions(): Option[] {
@@ -253,17 +278,6 @@ export default class Store {
253
278
  }, false) as Option[]
254
279
  }
255
280
 
256
- public getSelectedIDs(): string[] {
257
- let selectedOptions = this.getSelectedOptions()
258
-
259
- let selectedIDs: string[] = []
260
- selectedOptions.forEach((op: Option) => {
261
- selectedIDs.push(op.id)
262
- })
263
-
264
- return selectedIDs
265
- }
266
-
267
281
  public getOptgroupByID(id: string): Optgroup | null {
268
282
  // Loop through each data object
269
283
  // and if optgroup is found, return it
@@ -362,4 +376,32 @@ export default class Store {
362
376
  return dataSearch
363
377
  }
364
378
 
379
+ // Take in an array of options and reoder them based upon the selected order
380
+ public selectedOrderOptions(options: Option[]): Option[] {
381
+ const newOrder: Option[] = []
382
+ this.selectedOrder.forEach((id) => {
383
+ const option = options.find((opt) => opt.id === id)
384
+ if (option) {
385
+ newOrder.push(option)
386
+ }
387
+ })
388
+
389
+ // add any remaining options that were not in the selected order
390
+ options.forEach((option) => {
391
+ let isIn = false
392
+ newOrder.forEach((selectedOption) => {
393
+ if (option.id === selectedOption.id) {
394
+ isIn = true
395
+
396
+ return
397
+ }
398
+ })
399
+
400
+ if (!isIn) {
401
+ newOrder.push(option)
402
+ }
403
+ })
404
+
405
+ return newOrder
406
+ }
365
407
  }
@@ -1,6 +1,5 @@
1
1
  <script lang="ts">
2
2
  import { defineComponent, PropType } from 'vue'
3
-
4
3
  import SlimSelect, { Config, Events } from '../slim-select'
5
4
  import { SettingsPartial } from '../slim-select/settings'
6
5
  import { DataArrayPartial, Option } from '../slim-select/store'
@@ -9,31 +8,34 @@ export default defineComponent({
9
8
  name: 'SlimSelect',
10
9
  props: {
11
10
  modelValue: {
12
- type: [String, Array, undefined] as PropType<string | string[] | undefined>,
11
+ type: [String, Array, undefined] as PropType<string | string[] | undefined>
13
12
  },
14
13
  multiple: {
15
14
  type: Boolean,
16
- default: false,
15
+ default: false
17
16
  },
18
17
  data: {
19
- type: Array as PropType<DataArrayPartial>,
18
+ type: Array as PropType<DataArrayPartial>
20
19
  },
21
20
  settings: {
22
- type: Object as PropType<SettingsPartial>,
21
+ type: Object as PropType<SettingsPartial>
23
22
  },
24
23
  events: {
25
24
  type: Object as PropType<Events>,
26
- },
25
+ default: () => {
26
+ return {}
27
+ }
28
+ }
27
29
  },
28
30
  emits: ['update:modelValue'],
29
31
  data() {
30
32
  return {
31
- slim: null as SlimSelect | null,
33
+ slim: null as SlimSelect | null
32
34
  }
33
35
  },
34
36
  mounted() {
35
37
  let config = {
36
- select: this.$refs.slim,
38
+ select: this.$refs.slim
37
39
  } as Config
38
40
 
39
41
  // If data is passed in, use it
@@ -47,12 +49,12 @@ export default defineComponent({
47
49
  }
48
50
 
49
51
  // If events are passed in, use it
50
- config.events = this.events || {}
52
+ config.events = (this.events || {}) as Events
51
53
 
52
54
  // Wrap config.events.afterChange to run value update
53
55
  const ogAfterChange = config.events.afterChange
54
56
  config.events.afterChange = (newVal: Option[]) => {
55
- const value = this.multiple ? newVal.map((option) => option.value) : newVal.length > 0 ? newVal[0].value : '';
57
+ const value = this.multiple ? newVal.map((option) => option.value) : newVal.length > 0 ? newVal[0].value : ''
56
58
 
57
59
  // Check if value is different from modelValue
58
60
  if (this.value !== value) {
@@ -88,7 +90,7 @@ export default defineComponent({
88
90
  // Set the value of the select to the newVal
89
91
  this.slim?.setSelected(this.getCleanValue(newVal))
90
92
  },
91
- immediate: true,
93
+ immediate: true
92
94
  },
93
95
  data: {
94
96
  handler: function (newData) {
@@ -96,8 +98,8 @@ export default defineComponent({
96
98
  this.slim.setData(newData)
97
99
  }
98
100
  },
99
- deep: true,
100
- },
101
+ deep: true
102
+ }
101
103
  },
102
104
  computed: {
103
105
  value: {
@@ -106,8 +108,8 @@ export default defineComponent({
106
108
  },
107
109
  set(value: string | string[]) {
108
110
  this.$emit('update:modelValue', value)
109
- },
110
- },
111
+ }
112
+ }
111
113
  },
112
114
  methods: {
113
115
  // This allows via a ref to call the SlimSelect methods
@@ -128,8 +130,8 @@ export default defineComponent({
128
130
  }
129
131
 
130
132
  return multi ? [] : ''
131
- },
132
- },
133
+ }
134
+ }
133
135
  })
134
136
  </script>
135
137
 
package/tsconfig.json CHANGED
@@ -17,9 +17,8 @@
17
17
  "importHelpers": true,
18
18
  "lib": ["esnext", "dom"],
19
19
  "paths": {
20
- "slim-select": ["src/slim-select"],
21
- "@slim-select/vue": ["src/vue"]
20
+ "slim-select": ["src/slim-select"]
22
21
  }
23
22
  },
24
- "include": ["dist/", "src/**/*.ts", "src/**/*.d.ts", "src/**/*.vue", "src/react/src/index.tsx"]
23
+ "include": ["dist/", "src/**/*.ts", "src/**/*.d.ts"]
25
24
  }
@@ -3,6 +3,13 @@ import { defineConfig } from 'vite'
3
3
 
4
4
  // https://vitejs.dev/config/
5
5
  export default defineConfig({
6
+ css: {
7
+ preprocessorOptions: {
8
+ scss: {
9
+ api: 'modern-compiler' // or "modern"
10
+ }
11
+ }
12
+ },
6
13
  build: {
7
14
  outDir: 'docs',
8
15
  emptyOutDir: true,
@@ -10,9 +17,9 @@ export default defineConfig({
10
17
  output: {
11
18
  entryFileNames: `assets/[name].js`,
12
19
  chunkFileNames: `assets/[name].js`,
13
- assetFileNames: `assets/[name].[ext]`,
14
- },
15
- },
20
+ assetFileNames: `assets/[name].[ext]`
21
+ }
22
+ }
16
23
  },
17
- plugins: [vue()],
24
+ plugins: [vue()]
18
25
  })
@@ -1,2 +0,0 @@
1
- node_modules
2
- dist
@@ -1,24 +0,0 @@
1
- module.exports = {
2
- root: true,
3
- env: { browser: true, es2020: true, node: true },
4
- extends: [
5
- 'eslint:recommended',
6
- 'plugin:@typescript-eslint/recommended',
7
- 'plugin:react-hooks/recommended',
8
- 'plugin:react/recommended',
9
- 'plugin:@typescript-eslint/eslint-recommended',
10
- ],
11
- parser: '@typescript-eslint/parser',
12
- parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
13
- plugins: ['prettier', 'react-refresh'],
14
- rules: {
15
- 'react-hooks/rules-of-hooks': 'error',
16
- 'react-hooks/exhaustive-deps': 'warn',
17
- '@typescript-eslint/no-non-null-assertion': 'off',
18
- '@typescript-eslint/ban-ts-comment': 'off',
19
- '@typescript-eslint/no-explicit-any': 'off',
20
- '@typescript-eslint/no-extra-semi': 'off',
21
- '@typescript-eslint/no-unused-vars': 'off',
22
- '@typescript-eslint/no-invalid-void-type': 'off',
23
- },
24
- }
@@ -1,14 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>Slim Select React</title>
7
- </head>
8
- <body>
9
- <div id="react-root">
10
- <div id="react-hide"></div>
11
- </div>
12
- <script type="module" src="/src/frameworkpage.tsx"></script>
13
- </body>
14
- </html>
@@ -1,11 +0,0 @@
1
- {
2
- "transform": {
3
- "^.+\\.(t|j)sx?$": "ts-jest"
4
- },
5
- "testRegex": "(/tests/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$",
6
- "moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"],
7
- "testEnvironment": "jsdom",
8
- "moduleNameMapper": {
9
- "\\.(css|scss)$": "identity-obj-proxy"
10
- }
11
- }
@@ -1,32 +0,0 @@
1
- {
2
- "name": "@slim-select/react",
3
- "private": false,
4
- "description": "React integration",
5
- "version": "1.0.0",
6
- "keywords": [
7
- "react"
8
- ],
9
- "repository": {
10
- "type": "git",
11
- "url": "git+https://github.com/brianvoe/slim-select.git"
12
- },
13
- "author": "Brian Voelker <brian@webiswhatido.com> (http://webiswhatido.com)",
14
- "homepage": "https://slimselectjs.com/frameworks#vue",
15
- "license": "MIT",
16
- "type": "module",
17
- "scripts": {
18
- "dev": "vite",
19
- "build": "tsc && vite build",
20
- "lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
21
- "preview": "vite preview",
22
- "test": "jest --config jestconfig.json",
23
- "build:cjs": "tsc --module commonjs --outDir dist/cjs"
24
- },
25
- "main": "dist/slimselectreact.ssr.js",
26
- "browser": "dist/slimselect.global.js",
27
- "module": "dist/slimselectreact.es.js",
28
- "types": "dist/slimselect.react.d.ts",
29
- "files": [
30
- "dist"
31
- ]
32
- }
@@ -1,133 +0,0 @@
1
- import React from 'react'
2
- import ReactDOM from 'react-dom/client'
3
- import { SlimSelect } from '.'
4
- import { useState } from 'react'
5
-
6
- const ShowComponent = () => {
7
- const [simpleSingle, setSimpleSingle] = useState('2')
8
- const [simpleMultiple, setSimpleMultiple] = useState(['2', '3'])
9
-
10
- return (
11
- <div id="react" className="content">
12
- <h2 className="header">React</h2>
13
- <h3>Install</h3>
14
- <p>
15
- The react component is in a sub package under SlimSelect. All functionality still work in the implementation.
16
- </p>
17
- <div className="code-toolbar">
18
- <pre className="language-bash">
19
- <code>npm install @slim-select/react</code>
20
- </pre>
21
- </div>
22
- <br />
23
- <h3>Simple example</h3>
24
- <div style={{ display: 'flex', flexDirection: 'row', width: '100%' }}>
25
- <div style={{ flex: 0.5 }}>
26
- <strong>Value</strong> {simpleSingle}
27
- <SlimSelect
28
- modelValue={simpleSingle}
29
- events={{ afterChange: (values) => setSimpleSingle(values[0].value as unknown as string) }}
30
- style={{ marginLeft: '5px' }}
31
- ref={null}
32
- >
33
- <option value="all">All</option>
34
- <option value={'1'}>Option 1</option>
35
- <option value={'2'}>Option 2</option>
36
- <option value={'3'}>Option 3</option>
37
- </SlimSelect>
38
- </div>
39
- <div style={{ flex: 0.6, marginLeft: 15 }}>
40
- <div>
41
- <strong>Value</strong> {JSON.stringify(simpleMultiple)}
42
- </div>
43
- <SlimSelect
44
- modelValue={simpleMultiple}
45
- ref={null}
46
- multiple={true}
47
- events={{ afterChange: (values) => setSimpleMultiple(values.map((v) => v.value) as unknown as string[]) }}
48
- >
49
- <option value={'1'}>Option 1</option>
50
- <option value={'2'}>Option 2</option>
51
- <option value={'3'}>Value 3</option>
52
- </SlimSelect>
53
- </div>
54
- </div>
55
- <div className="code-toolbar">
56
- <pre className="language-javascript">
57
- <code className="language-javascript">
58
- import React from &quot;react&quot; <br />
59
- import SlimSelect from &quot;@slim-select/react&quot; <br />
60
- import {`{`} useState {`}`} from &quot;react&quot;
61
- <br />
62
- <br />
63
- export default MySelect = () {`=>`} {`{`}
64
- <br />
65
- const [simpleSingle, setSimpleSingle] = useState(&quot;2&quot;) <br />
66
- return ( <br />
67
- &lt;SlimSelect <br />
68
- modelValue= {`{`}simpleSingle{`}`}
69
- <br />
70
- events={`{{ afterChange: (values) => setSimpleSingle(values[0].value as unknown as string) }}`}
71
- &gt; <br />
72
- &lt;option value=&quot;all&quot;&gt;All&lt;/option&gt; <br />
73
- &lt;option value=&quot;1&quot;&gt;Option 1&lt;/option&gt; <br />
74
- &lt;option value=&quot;2&quot;&gt;Option 2&lt;/option&gt; <br />
75
- &lt;option value=&quot;3&quot;&gt;Option 3&lt;/option&gt; <br />
76
- &lt;/SlimSelect&gt; <br /> ){`}`}
77
- </code>
78
- </pre>
79
- </div>
80
-
81
- <br />
82
- <div className="separator"></div>
83
- <br />
84
-
85
- <h3>Attributes</h3>
86
- <p>There are certain attributes that are reactive to changes</p>
87
-
88
- <h4>disabled</h4>
89
- <SlimSelect settings={{ disabled: true }}>
90
- <option value={'1'}>Option 1</option>
91
- <option value={'2'}>Option 2</option>
92
- <option value={'3'}>Value 3</option>
93
- </SlimSelect>
94
- <div className="code-toolbar">
95
- <pre className="language-javascript">
96
- <code className="language-javascript">
97
- import React from &quot;react&quot; <br />
98
- import SlimSelect from &quot;@slim-select/react&quot; <br />
99
- import {`{`} useState {`}`} from &quot;react&quot;
100
- <br />
101
- <br />
102
- export default MySelect = () {`=>`} {`{`}
103
- <br />
104
- const [simpleSingle, setSimpleSingle] = useState(&quot;2&quot;) <br />
105
- return ( <br />
106
- &lt;SlimSelect <br />
107
- settings={`{`}
108
- {`{`}disabled: true {`}`}
109
- {`}`}&gt;
110
- <br />
111
- &lt;option value=&quot;all&quot;&gt;All&lt;/option&gt; <br />
112
- &lt;option value=&quot;1&quot;&gt;Option 1&lt;/option&gt; <br />
113
- &lt;option value=&quot;2&quot;&gt;Option 2&lt;/option&gt; <br />
114
- &lt;option value=&quot;3&quot;&gt;Option 3&lt;/option&gt; <br />
115
- &lt;/SlimSelect&gt; <br /> ){`}`}
116
- </code>
117
- </pre>
118
- </div>
119
- </div>
120
- )
121
- }
122
- const timeout = document.getElementById('app') ? 100 : 0
123
- ;(function () {
124
- const interval = window.setInterval(() => {
125
- if (document.getElementById('react-root') != null && document.getElementById('react-hide') != null) {
126
- ReactDOM.createRoot(document.getElementById('react-root') as HTMLElement).render(
127
- <React.StrictMode>
128
- <ShowComponent />
129
- </React.StrictMode>,
130
- )
131
- }
132
- }, timeout)
133
- })()
@@ -1,3 +0,0 @@
1
- import SlimSelect, { SlimSelectProps, SlimSelectRef } from './slimselect'
2
- export { SlimSelect }
3
- export type { SlimSelectProps, SlimSelectRef }