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
@@ -1,11 +1,14 @@
1
1
  import { debounce } from './helpers'
2
2
  import Settings from './settings'
3
3
  import Store, { DataArray, Optgroup, Option, OptionOptional } from './store'
4
+ import CssClasses from './classes'
4
5
 
5
6
  export interface Callbacks {
6
7
  open: () => void
7
8
  close: () => void
8
- addable?: (value: string) => Promise<OptionOptional | string> | OptionOptional | string | false | undefined | null
9
+ addable?: (
10
+ value: string
11
+ ) => Promise<OptionOptional | string> | OptionOptional | string | false | undefined | null | Error
9
12
  setSelected: (value: string | string[], runAfterChange: boolean) => void
10
13
  addOption: (option: Option) => void
11
14
  search: (search: string) => void
@@ -53,73 +56,12 @@ export default class Render {
53
56
  public content: Content
54
57
 
55
58
  // Classes
56
- public classes = {
57
- // Main
58
- main: 'ss-main',
59
-
60
- // Placeholder
61
- placeholder: 'ss-placeholder',
62
-
63
- // Values
64
- values: 'ss-values',
65
- single: 'ss-single',
66
- max: 'ss-max',
67
- value: 'ss-value',
68
- valueText: 'ss-value-text',
69
- valueDelete: 'ss-value-delete',
70
- valueOut: 'ss-value-out',
71
-
72
- // Deselect
73
- deselect: 'ss-deselect',
74
- deselectPath: 'M10,10 L90,90 M10,90 L90,10', // Not a class but whatever
75
-
76
- // Arrow
77
- arrow: 'ss-arrow',
78
- arrowClose: 'M10,30 L50,70 L90,30', // Not a class but whatever
79
- arrowOpen: 'M10,70 L50,30 L90,70', // Not a class but whatever
80
-
81
- // Content
82
- content: 'ss-content',
83
- openAbove: 'ss-open-above',
84
- openBelow: 'ss-open-below',
85
-
86
- // Search
87
- search: 'ss-search',
88
- searchHighlighter: 'ss-search-highlight',
89
- searching: 'ss-searching',
90
- addable: 'ss-addable',
91
- addablePath: 'M50,10 L50,90 M10,50 L90,50', // Not a class but whatever
92
-
93
- // List optgroups/options
94
- list: 'ss-list',
95
-
96
- // Optgroup
97
- optgroup: 'ss-optgroup',
98
- optgroupLabel: 'ss-optgroup-label',
99
- optgroupLabelText: 'ss-optgroup-label-text',
100
- optgroupActions: 'ss-optgroup-actions',
101
- optgroupSelectAll: 'ss-selectall', // optgroup select all
102
- optgroupSelectAllBox: 'M60,10 L10,10 L10,90 L90,90 L90,50', // Not a class but whatever
103
- optgroupSelectAllCheck: 'M30,45 L50,70 L90,10', // Not a class but whatever
104
- optgroupClosable: 'ss-closable',
105
-
106
- // Option
107
- option: 'ss-option',
108
- optionDelete: 'M10,10 L90,90 M10,90 L90,10', // Not a class but whatever
109
- highlighted: 'ss-highlighted',
110
-
111
- // Misc
112
- open: 'ss-open',
113
- close: 'ss-close',
114
- selected: 'ss-selected',
115
- error: 'ss-error',
116
- disabled: 'ss-disabled',
117
- hide: 'ss-hide',
118
- }
59
+ public classes: CssClasses
119
60
 
120
- constructor(settings: Required<Settings>, store: Store, callbacks: Callbacks) {
61
+ constructor(settings: Required<Settings>, classes: Required<CssClasses>, store: Store, callbacks: Callbacks) {
121
62
  this.store = store
122
63
  this.settings = settings
64
+ this.classes = classes
123
65
  this.callbacks = callbacks
124
66
 
125
67
  this.main = this.mainDiv()
@@ -130,7 +72,9 @@ export default class Render {
130
72
  this.updateAriaAttributes()
131
73
 
132
74
  // Add content to the content location settings
133
- this.settings.contentLocation.appendChild(this.content.main)
75
+ if (this.settings.contentLocation) {
76
+ this.settings.contentLocation.appendChild(this.content.main)
77
+ }
134
78
  }
135
79
 
136
80
  // Remove disabled classes
@@ -265,7 +209,7 @@ export default class Render {
265
209
  return false
266
210
  }
267
211
 
268
- return false
212
+ return true
269
213
  }
270
214
 
271
215
  // Add onclick for main div
@@ -321,9 +265,9 @@ export default class Render {
321
265
  } else {
322
266
  // Get first option and set it as selected
323
267
  const firstOption = this.store.getFirstOption()
324
- const value = firstOption ? firstOption.value : ''
268
+ const id = firstOption ? firstOption.id : ''
325
269
 
326
- this.callbacks.setSelected(value, false)
270
+ this.callbacks.setSelected(id, false)
327
271
  }
328
272
 
329
273
  // Check if we need to close the dropdown
@@ -365,12 +309,12 @@ export default class Render {
365
309
  deselect: {
366
310
  main: deselect,
367
311
  svg: deselectSvg,
368
- path: deselectPath,
312
+ path: deselectPath
369
313
  },
370
314
  arrow: {
371
315
  main: arrow,
372
- path: arrowPath,
373
- },
316
+ path: arrowPath
317
+ }
374
318
  }
375
319
  }
376
320
 
@@ -491,6 +435,11 @@ export default class Render {
491
435
  }
492
436
  }
493
437
 
438
+ // Lets check for data selected order
439
+ if (this.settings.keepOrder) {
440
+ selectedOptions = this.store.selectedOrderOptions(selectedOptions)
441
+ }
442
+
494
443
  // Loop through currentNodes and only include ones that are not in selectedIDs
495
444
  let removeNodes: HTMLDivElement[] = []
496
445
  for (let i = 0; i < currentNodes.length; i++) {
@@ -555,7 +504,7 @@ export default class Render {
555
504
 
556
505
  const text = document.createElement('div')
557
506
  text.classList.add(this.classes.valueText)
558
- text.innerText = option.text // For multiple values always use text
507
+ text.textContent = option.text // For multiple values always use text
559
508
  value.appendChild(text)
560
509
 
561
510
  // Only add deletion if the option is not mandatory
@@ -592,20 +541,20 @@ export default class Render {
592
541
  }
593
542
 
594
543
  if (shouldDelete) {
595
- // Loop through after and append values to a variable called selected
596
- let selectedValues: string[] = []
544
+ // Loop through after and append ids to a variable called selected
545
+ let selectedIds: string[] = []
597
546
  for (const o of after) {
598
547
  if (o instanceof Optgroup) {
599
548
  for (const c of o.options) {
600
- selectedValues.push(c.value)
549
+ selectedIds.push(c.id)
601
550
  }
602
551
  }
603
552
 
604
553
  if (o instanceof Option) {
605
- selectedValues.push(o.value)
554
+ selectedIds.push(o.id)
606
555
  }
607
556
  }
608
- this.callbacks.setSelected(selectedValues, false)
557
+ this.callbacks.setSelected(selectedIds, false)
609
558
 
610
559
  // Check if we need to close the dropdown
611
560
  if (this.settings.closeOnSelect) {
@@ -653,7 +602,7 @@ export default class Render {
653
602
  return {
654
603
  main: main,
655
604
  search: search,
656
- list: list,
605
+ list: list
657
606
  }
658
607
  }
659
608
 
@@ -690,7 +639,7 @@ export default class Render {
690
639
  // Setup search return object
691
640
  const searchReturn: Search = {
692
641
  main,
693
- input,
642
+ input
694
643
  }
695
644
 
696
645
  // We still want the search to be tabable but not shown
@@ -724,14 +673,19 @@ export default class Render {
724
673
  // which will also focus on main div
725
674
  // and then continuing normal tabbing
726
675
  this.callbacks.close()
727
-
728
676
  return true // Continue doing normal tabbing
729
677
  case 'Escape':
730
678
  this.callbacks.close()
731
679
  return false
732
- case 'Enter':
733
680
  case ' ':
734
- if (this.callbacks.addable && e.ctrlKey) {
681
+ const highlighted = this.content.list.querySelector('.' + this.classes.highlighted) as HTMLDivElement
682
+ if (highlighted) {
683
+ highlighted.click()
684
+ return false
685
+ }
686
+ return true
687
+ case 'Enter':
688
+ if (this.callbacks.addable) {
735
689
  addable.click()
736
690
  return false
737
691
  } else {
@@ -790,11 +744,11 @@ export default class Render {
790
744
 
791
745
  // set selected value for single and multiple
792
746
  if (this.settings.isMultiple) {
793
- let values = this.store.getSelected()
794
- values.push(newOption.value)
795
- this.callbacks.setSelected(values, true)
747
+ let ids = this.store.getSelected()
748
+ ids.push(newOption.id)
749
+ this.callbacks.setSelected(ids, true)
796
750
  } else {
797
- this.callbacks.setSelected([newOption.value], true)
751
+ this.callbacks.setSelected([newOption.id], true)
798
752
  }
799
753
 
800
754
  // Clear search
@@ -823,8 +777,10 @@ export default class Render {
823
777
  if (typeof value === 'string') {
824
778
  runFinish({
825
779
  text: value,
826
- value: value,
780
+ value: value
827
781
  })
782
+ } else if (addableValue instanceof Error) {
783
+ this.renderError(addableValue.message)
828
784
  } else {
829
785
  runFinish(value)
830
786
  }
@@ -832,8 +788,10 @@ export default class Render {
832
788
  } else if (typeof addableValue === 'string') {
833
789
  runFinish({
834
790
  text: addableValue,
835
- value: addableValue,
791
+ value: addableValue
836
792
  })
793
+ } else if (addableValue instanceof Error) {
794
+ this.renderError(addableValue.message)
837
795
  } else {
838
796
  runFinish(addableValue)
839
797
  }
@@ -846,7 +804,7 @@ export default class Render {
846
804
  searchReturn.addable = {
847
805
  main: addable,
848
806
  svg: plus,
849
- path: plusPath,
807
+ path: plusPath
850
808
  }
851
809
  }
852
810
 
@@ -991,11 +949,34 @@ export default class Render {
991
949
  if (data.length === 0) {
992
950
  const noResults = document.createElement('div')
993
951
  noResults.classList.add(this.classes.search)
994
- noResults.innerHTML = this.settings.searchText
952
+
953
+ //
954
+ if (this.callbacks.addable) {
955
+ noResults.innerHTML = this.settings.addableText.replace('{value}', this.content.search.input.value)
956
+ } else {
957
+ noResults.innerHTML = this.settings.searchText
958
+ }
995
959
  this.content.list.appendChild(noResults)
996
960
  return
997
961
  }
998
962
 
963
+ // If settings has allowDeselect and isSingle, add empty placeholder in the event they want to deselect
964
+ if (this.settings.allowDeselect && !this.settings.isMultiple) {
965
+ // Check if store options have a placeholder
966
+ const placeholderOption = this.store.filter((o) => o.placeholder, false) as Option[]
967
+ if (!placeholderOption.length) {
968
+ this.store.addOption(
969
+ new Option({
970
+ text: '',
971
+ value: '',
972
+ selected: false,
973
+ placeholder: true
974
+ }),
975
+ true
976
+ )
977
+ }
978
+ }
979
+
999
980
  // Append individual options to div container
1000
981
  for (const d of data) {
1001
982
  // Create optgroup
@@ -1074,7 +1055,7 @@ export default class Render {
1074
1055
  // Put together new list minus all options in this optgroup
1075
1056
  const newSelected = currentSelected.filter((s) => {
1076
1057
  for (const o of d.options) {
1077
- if (s === o.value) {
1058
+ if (s === o.id) {
1078
1059
  return false
1079
1060
  }
1080
1061
  }
@@ -1086,7 +1067,7 @@ export default class Render {
1086
1067
  return
1087
1068
  } else {
1088
1069
  // Put together new list with all options in this optgroup
1089
- const newSelected = currentSelected.concat(d.options.map((o) => o.value))
1070
+ const newSelected = currentSelected.concat(d.options.map((o) => o.id))
1090
1071
 
1091
1072
  // Loop through options and if they don't exist in the store
1092
1073
  // run addOption callback
@@ -1203,7 +1184,7 @@ export default class Render {
1203
1184
  optionEl.innerHTML = this.highlightText(
1204
1185
  option.html !== '' ? option.html : option.text,
1205
1186
  this.content.search.input.value,
1206
- this.classes.searchHighlighter,
1187
+ this.classes.searchHighlighter
1207
1188
  )
1208
1189
  } else if (option.html !== '') {
1209
1190
  optionEl.innerHTML = option.html
@@ -1315,8 +1296,8 @@ export default class Render {
1315
1296
 
1316
1297
  // Get values from after and set as selected
1317
1298
  this.callbacks.setSelected(
1318
- after.map((o: Option) => o.value),
1319
- false,
1299
+ after.map((o: Option) => o.id),
1300
+ false
1320
1301
  )
1321
1302
 
1322
1303
  // If closeOnSelect is true
@@ -1345,7 +1326,7 @@ export default class Render {
1345
1326
  private highlightText(str: string, search: any, className: string) {
1346
1327
  // the completed string will be itself if already set, otherwise, the string that was passed in
1347
1328
  let completedString: any = str
1348
- const regex = new RegExp('(' + search.trim() + ')(?![^<]*>[^<>]*</)', 'i')
1329
+ const regex = new RegExp('(?![^<]*>)(' + search.trim() + ')(?![^<]*>[^<>]*</)', 'i')
1349
1330
 
1350
1331
  // If the regex doesn't match the string just exit
1351
1332
  if (!str.match(regex)) {
@@ -11,7 +11,7 @@ export default [
11
11
  output: {
12
12
  file: '../../dist/slimselect.cjs.js',
13
13
  format: 'cjs',
14
- exports: 'default',
14
+ exports: 'default'
15
15
  },
16
16
  plugins: [
17
17
  typescript(),
@@ -27,12 +27,12 @@ export default [
27
27
  {
28
28
  modules: false,
29
29
  useBuiltIns: 'usage',
30
- targets: 'maintained node versions',
31
- },
32
- ],
33
- ],
34
- }),
35
- ],
30
+ targets: 'maintained node versions'
31
+ }
32
+ ]
33
+ ]
34
+ })
35
+ ]
36
36
  },
37
37
 
38
38
  // UMD build for browsers
@@ -42,13 +42,13 @@ export default [
42
42
  {
43
43
  name: 'SlimSelect',
44
44
  file: '../../dist/slimselect.js',
45
- format: 'umd',
45
+ format: 'umd'
46
46
  },
47
47
  {
48
48
  name: 'SlimSelect',
49
49
  file: '../../dist/slimselect.umd.js',
50
- format: 'umd',
51
- },
50
+ format: 'umd'
51
+ }
52
52
  ],
53
53
  plugins: [
54
54
  typescript(),
@@ -56,9 +56,9 @@ export default [
56
56
  commonjs(),
57
57
  babel({
58
58
  babelHelpers: 'bundled',
59
- exclude: 'node_modules/**',
60
- }),
61
- ],
59
+ exclude: 'node_modules/**'
60
+ })
61
+ ]
62
62
  },
63
63
 
64
64
  // UMD build for browsers minified with terser
@@ -68,13 +68,13 @@ export default [
68
68
  {
69
69
  name: 'SlimSelect',
70
70
  file: '../../dist/slimselect.min.js',
71
- format: 'umd',
71
+ format: 'umd'
72
72
  },
73
73
  {
74
74
  name: 'SlimSelect',
75
75
  file: '../../dist/slimselect.umd.min.js',
76
- format: 'umd',
77
- },
76
+ format: 'umd'
77
+ }
78
78
  ],
79
79
  plugins: [
80
80
  typescript(),
@@ -82,10 +82,10 @@ export default [
82
82
  commonjs(),
83
83
  babel({
84
84
  babelHelpers: 'bundled',
85
- exclude: 'node_modules/**',
85
+ exclude: 'node_modules/**'
86
86
  }),
87
- terser(),
88
- ],
87
+ terser()
88
+ ]
89
89
  },
90
90
 
91
91
  // ES module build for modern browsers
@@ -93,7 +93,7 @@ export default [
93
93
  input: './index.ts',
94
94
  output: {
95
95
  file: '../../dist/slimselect.es.js',
96
- format: 'es',
96
+ format: 'es'
97
97
  },
98
98
  plugins: [
99
99
  typescript(),
@@ -101,9 +101,9 @@ export default [
101
101
  commonjs(),
102
102
  babel({
103
103
  babelHelpers: 'bundled',
104
- exclude: 'node_modules/**',
105
- }),
106
- ],
104
+ exclude: 'node_modules/**'
105
+ })
106
+ ]
107
107
  },
108
108
 
109
109
  // IIFE build for modern browsers
@@ -112,7 +112,7 @@ export default [
112
112
  output: {
113
113
  name: 'SlimSelect',
114
114
  file: '../../dist/slimselect.global.js',
115
- format: 'iife',
115
+ format: 'iife'
116
116
  },
117
117
  plugins: [
118
118
  typescript(),
@@ -120,8 +120,8 @@ export default [
120
120
  commonjs(),
121
121
  babel({
122
122
  babelHelpers: 'bundled',
123
- exclude: 'node_modules/**',
124
- }),
125
- ],
126
- },
123
+ exclude: 'node_modules/**'
124
+ })
125
+ ]
126
+ }
127
127
  ]