@coreui/vue-pro 4.8.2 → 4.9.0-beta.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 (226) hide show
  1. package/README.md +1 -1
  2. package/dist/components/accordion/CAccordion.d.ts +1 -1
  3. package/dist/components/accordion/CAccordionBody.d.ts +1 -1
  4. package/dist/components/accordion/CAccordionButton.d.ts +1 -1
  5. package/dist/components/accordion/CAccordionHeader.d.ts +1 -1
  6. package/dist/components/accordion/CAccordionItem.d.ts +1 -1
  7. package/dist/components/alert/CAlert.d.ts +1 -1
  8. package/dist/components/alert/CAlertHeading.d.ts +1 -1
  9. package/dist/components/alert/CAlertLink.d.ts +1 -1
  10. package/dist/components/avatar/CAvatar.d.ts +1 -1
  11. package/dist/components/backdrop/CBackdrop.d.ts +1 -1
  12. package/dist/components/badge/CBadge.d.ts +1 -1
  13. package/dist/components/breadcrumb/CBreadcrumb.d.ts +1 -1
  14. package/dist/components/breadcrumb/CBreadcrumbItem.d.ts +1 -1
  15. package/dist/components/button/CButton.d.ts +1 -1
  16. package/dist/components/button-group/CButtonGroup.d.ts +1 -1
  17. package/dist/components/button-group/CButtonToolbar.d.ts +1 -1
  18. package/dist/components/calendar/CCalendar.d.ts +33 -1
  19. package/dist/components/callout/CCallout.d.ts +1 -1
  20. package/dist/components/card/CCard.d.ts +1 -1
  21. package/dist/components/card/CCardBody.d.ts +1 -1
  22. package/dist/components/card/CCardFooter.d.ts +1 -1
  23. package/dist/components/card/CCardGroup.d.ts +1 -1
  24. package/dist/components/card/CCardHeader.d.ts +1 -1
  25. package/dist/components/card/CCardImage.d.ts +1 -1
  26. package/dist/components/card/CCardImageOverlay.d.ts +1 -1
  27. package/dist/components/card/CCardLink.d.ts +1 -1
  28. package/dist/components/card/CCardSubtitle.d.ts +1 -1
  29. package/dist/components/card/CCardText.d.ts +1 -1
  30. package/dist/components/card/CCardTitle.d.ts +1 -1
  31. package/dist/components/carousel/CCarousel.d.ts +1 -1
  32. package/dist/components/carousel/CCarouselCaption.d.ts +1 -1
  33. package/dist/components/carousel/CCarouselItem.d.ts +1 -1
  34. package/dist/components/close-button/CCloseButton.d.ts +1 -1
  35. package/dist/components/collapse/CCollapse.d.ts +1 -1
  36. package/dist/components/date-picker/CDatePicker.d.ts +35 -3
  37. package/dist/components/date-range-picker/CDateRangePicker.d.ts +89 -78
  38. package/dist/components/date-range-picker/utils.d.ts +1 -0
  39. package/dist/components/dropdown/CDropdown.d.ts +2 -2
  40. package/dist/components/dropdown/CDropdownDivider.d.ts +1 -1
  41. package/dist/components/dropdown/CDropdownHeader.d.ts +1 -1
  42. package/dist/components/dropdown/CDropdownItem.d.ts +1 -1
  43. package/dist/components/dropdown/CDropdownMenu.d.ts +1 -1
  44. package/dist/components/dropdown/CDropdownToggle.d.ts +1 -1
  45. package/dist/components/element-cover/CElementCover.d.ts +1 -1
  46. package/dist/components/footer/CFooter.d.ts +1 -1
  47. package/dist/components/form/CForm.d.ts +1 -1
  48. package/dist/components/form/CFormCheck.d.ts +10 -2
  49. package/dist/components/form/CFormControl.d.ts +2 -2
  50. package/dist/components/form/CFormControlValidation.d.ts +1 -1
  51. package/dist/components/form/CFormControlWrapper.d.ts +1 -1
  52. package/dist/components/form/CFormFeedback.d.ts +1 -1
  53. package/dist/components/form/CFormFloating.d.ts +1 -1
  54. package/dist/components/form/CFormInput.d.ts +12 -12
  55. package/dist/components/form/CFormLabel.d.ts +1 -1
  56. package/dist/components/form/CFormRange.d.ts +1 -1
  57. package/dist/components/form/CFormSelect.d.ts +1 -1
  58. package/dist/components/form/CFormSwitch.d.ts +1 -1
  59. package/dist/components/form/CFormText.d.ts +1 -1
  60. package/dist/components/form/CFormTextarea.d.ts +3 -3
  61. package/dist/components/form/CInputGroup.d.ts +1 -1
  62. package/dist/components/form/CInputGroupText.d.ts +1 -1
  63. package/dist/components/grid/CCol.d.ts +1 -1
  64. package/dist/components/grid/CContainer.d.ts +1 -1
  65. package/dist/components/grid/CRow.d.ts +1 -1
  66. package/dist/components/header/CHeader.d.ts +1 -1
  67. package/dist/components/header/CHeaderBrand.d.ts +1 -1
  68. package/dist/components/header/CHeaderDivider.d.ts +1 -1
  69. package/dist/components/header/CHeaderNav.d.ts +1 -1
  70. package/dist/components/header/CHeaderText.d.ts +1 -1
  71. package/dist/components/header/CHeaderToggler.d.ts +1 -1
  72. package/dist/components/image/CImage.d.ts +1 -1
  73. package/dist/components/link/CLink.d.ts +1 -1
  74. package/dist/components/list-group/CListGroup.d.ts +1 -1
  75. package/dist/components/list-group/CListGroupItem.d.ts +1 -1
  76. package/dist/components/loading-button/CLoadingButton.d.ts +1 -1
  77. package/dist/components/modal/CModal.d.ts +1 -1
  78. package/dist/components/modal/CModalBody.d.ts +1 -1
  79. package/dist/components/modal/CModalFooter.d.ts +1 -1
  80. package/dist/components/modal/CModalHeader.d.ts +1 -1
  81. package/dist/components/modal/CModalTitle.d.ts +1 -1
  82. package/dist/components/multi-select/CMultiSelect.d.ts +73 -59
  83. package/dist/components/multi-select/CMultiSelectNativeSelect.d.ts +9 -33
  84. package/dist/components/multi-select/CMultiSelectOptions.d.ts +12 -41
  85. package/dist/components/multi-select/CMultiSelectSelection.d.ts +6 -59
  86. package/dist/components/multi-select/types.d.ts +8 -3
  87. package/dist/components/multi-select/utils.d.ts +9 -4
  88. package/dist/components/nav/CNav.d.ts +1 -1
  89. package/dist/components/nav/CNavGroup.d.ts +1 -1
  90. package/dist/components/nav/CNavGroupItems.d.ts +1 -1
  91. package/dist/components/nav/CNavItem.d.ts +1 -1
  92. package/dist/components/nav/CNavLink.d.ts +1 -1
  93. package/dist/components/nav/CNavTitle.d.ts +1 -1
  94. package/dist/components/navbar/CNavbar.d.ts +1 -1
  95. package/dist/components/navbar/CNavbarBrand.d.ts +1 -1
  96. package/dist/components/navbar/CNavbarNav.d.ts +1 -1
  97. package/dist/components/navbar/CNavbarText.d.ts +1 -1
  98. package/dist/components/navbar/CNavbarToggler.d.ts +1 -1
  99. package/dist/components/offcanvas/COffcanvas.d.ts +1 -1
  100. package/dist/components/offcanvas/COffcanvasBody.d.ts +1 -1
  101. package/dist/components/offcanvas/COffcanvasHeader.d.ts +1 -1
  102. package/dist/components/offcanvas/COffcanvasTitle.d.ts +1 -1
  103. package/dist/components/pagination/CPagination.d.ts +1 -1
  104. package/dist/components/pagination/CPaginationItem.d.ts +1 -1
  105. package/dist/components/picker/CPicker.d.ts +57 -7
  106. package/dist/components/placeholder/CPlaceholder.d.ts +1 -1
  107. package/dist/components/popover/CPopover.d.ts +2 -2
  108. package/dist/components/progress/CProgress.d.ts +1 -1
  109. package/dist/components/progress/CProgressBar.d.ts +1 -1
  110. package/dist/components/sidebar/CSidebar.d.ts +1 -1
  111. package/dist/components/sidebar/CSidebarBrand.d.ts +1 -1
  112. package/dist/components/sidebar/CSidebarFooter.d.ts +1 -1
  113. package/dist/components/sidebar/CSidebarHeader.d.ts +1 -1
  114. package/dist/components/sidebar/CSidebarNav.d.ts +1 -1
  115. package/dist/components/sidebar/CSidebarToggler.d.ts +1 -1
  116. package/dist/components/smart-pagination/CSmartPagination.d.ts +1 -1
  117. package/dist/components/smart-table/CSmartTable.d.ts +20 -56
  118. package/dist/components/smart-table/CSmartTableBody.d.ts +1 -1
  119. package/dist/components/smart-table/CSmartTableCleaner.d.ts +1 -1
  120. package/dist/components/smart-table/CSmartTableFilter.d.ts +1 -1
  121. package/dist/components/smart-table/CSmartTableHead.d.ts +10 -1
  122. package/dist/components/smart-table/CSmartTableItemsPerPageSelector.d.ts +1 -1
  123. package/dist/components/smart-table/types.d.ts +12 -0
  124. package/dist/components/smart-table/utils.d.ts +12 -2
  125. package/dist/components/spinner/CSpinner.d.ts +1 -1
  126. package/dist/components/table/CTable.d.ts +1 -1
  127. package/dist/components/table/CTableBody.d.ts +1 -1
  128. package/dist/components/table/CTableCaption.d.ts +1 -1
  129. package/dist/components/table/CTableDataCell.d.ts +1 -1
  130. package/dist/components/table/CTableFoot.d.ts +1 -1
  131. package/dist/components/table/CTableHead.d.ts +1 -1
  132. package/dist/components/table/CTableHeaderCell.d.ts +1 -1
  133. package/dist/components/table/CTableRow.d.ts +1 -1
  134. package/dist/components/tabs/CTabContent.d.ts +1 -1
  135. package/dist/components/tabs/CTabPane.d.ts +1 -1
  136. package/dist/components/time-picker/CTimePicker.d.ts +1 -1
  137. package/dist/components/time-picker/CTimePickerRollCol.d.ts +1 -1
  138. package/dist/components/toast/CToast.d.ts +1 -1
  139. package/dist/components/toast/CToastBody.d.ts +1 -1
  140. package/dist/components/toast/CToastClose.d.ts +1 -1
  141. package/dist/components/toast/CToastHeader.d.ts +1 -1
  142. package/dist/components/toast/CToaster.d.ts +1 -1
  143. package/dist/components/tooltip/CTooltip.d.ts +2 -2
  144. package/dist/components/virtual-scroller/CVirtualScroller.d.ts +1 -1
  145. package/dist/components/widgets/CWidgetStatsA.d.ts +1 -1
  146. package/dist/components/widgets/CWidgetStatsB.d.ts +1 -1
  147. package/dist/components/widgets/CWidgetStatsC.d.ts +1 -1
  148. package/dist/components/widgets/CWidgetStatsD.d.ts +1 -1
  149. package/dist/components/widgets/CWidgetStatsE.d.ts +1 -1
  150. package/dist/components/widgets/CWidgetStatsF.d.ts +1 -1
  151. package/dist/composables/index.d.ts +2 -0
  152. package/dist/composables/useColorModes.d.ts +5 -0
  153. package/dist/directives/index.d.ts +1 -1
  154. package/dist/directives/v-c-visible.d.ts +1 -1
  155. package/dist/index.d.ts +2 -1
  156. package/dist/index.es.js +4224 -4159
  157. package/dist/index.es.js.map +1 -1
  158. package/dist/index.js +4226 -4160
  159. package/dist/index.js.map +1 -1
  160. package/dist/utils/getUID.d.ts +2 -0
  161. package/dist/utils/index.d.ts +4 -1
  162. package/dist/utils/isObjectInArray.d.ts +2 -0
  163. package/dist/utils/isRTL.d.ts +2 -0
  164. package/package.json +11 -11
  165. package/src/components/accordion/CAccordionItem.ts +2 -2
  166. package/src/components/backdrop/CBackdrop.ts +1 -1
  167. package/src/components/calendar/CCalendar.ts +111 -49
  168. package/src/components/carousel/CCarousel.ts +7 -7
  169. package/src/components/date-picker/CDatePicker.ts +16 -1
  170. package/src/components/date-range-picker/CDateRangePicker.ts +179 -128
  171. package/src/components/date-range-picker/utils.ts +49 -0
  172. package/src/components/dropdown/CDropdown.ts +34 -31
  173. package/src/components/dropdown/CDropdownMenu.ts +1 -1
  174. package/src/components/dropdown/CDropdownToggle.ts +1 -1
  175. package/src/components/element-cover/CElementCover.ts +1 -0
  176. package/src/components/form/CFormCheck.ts +10 -4
  177. package/src/components/form/CFormInput.ts +2 -2
  178. package/src/components/form/CFormLabel.ts +1 -1
  179. package/src/components/form/CFormSelect.ts +1 -1
  180. package/src/components/grid/CCol.ts +1 -1
  181. package/src/components/grid/CContainer.ts +1 -1
  182. package/src/components/header/CHeader.ts +1 -1
  183. package/src/components/modal/CModal.ts +1 -0
  184. package/src/components/multi-select/CMultiSelect.ts +337 -144
  185. package/src/components/multi-select/CMultiSelectNativeSelect.ts +8 -15
  186. package/src/components/multi-select/CMultiSelectOptions.ts +32 -39
  187. package/src/components/multi-select/CMultiSelectSelection.ts +24 -40
  188. package/src/components/multi-select/types.ts +10 -4
  189. package/src/components/multi-select/utils.ts +71 -37
  190. package/src/components/nav/CNavGroup.ts +4 -0
  191. package/src/components/navbar/CNavbar.ts +1 -1
  192. package/src/components/navbar/CNavbarBrand.ts +1 -1
  193. package/src/components/offcanvas/COffcanvas.ts +3 -2
  194. package/src/components/pagination/CPaginationItem.ts +1 -1
  195. package/src/components/picker/CPicker.ts +106 -157
  196. package/src/components/popover/CPopover.ts +18 -2
  197. package/src/components/props.ts +2 -6
  198. package/src/components/sidebar/CSidebar.ts +3 -2
  199. package/src/components/smart-table/CSmartTable.ts +45 -52
  200. package/src/components/smart-table/CSmartTableBody.ts +5 -3
  201. package/src/components/smart-table/CSmartTableHead.ts +41 -14
  202. package/src/components/smart-table/types.ts +13 -0
  203. package/src/components/smart-table/utils.ts +119 -21
  204. package/src/components/spinner/CSpinner.ts +4 -2
  205. package/src/components/table/CTable.ts +19 -18
  206. package/src/components/table/types.ts +19 -19
  207. package/src/components/time-picker/CTimePicker.ts +216 -125
  208. package/src/components/toast/CToast.ts +1 -1
  209. package/src/components/tooltip/CTooltip.ts +19 -3
  210. package/src/components/virtual-scroller/CVirtualScroller.ts +10 -8
  211. package/src/components/widgets/CWidgetStatsA.ts +1 -1
  212. package/src/components/widgets/CWidgetStatsB.ts +1 -1
  213. package/src/components/widgets/CWidgetStatsC.ts +1 -1
  214. package/src/components/widgets/CWidgetStatsE.ts +1 -1
  215. package/src/components/widgets/CWidgetStatsF.ts +1 -1
  216. package/src/composables/index.ts +3 -0
  217. package/src/composables/useColorModes.ts +57 -0
  218. package/src/directives/index.ts +1 -1
  219. package/src/directives/v-c-popover.ts +9 -13
  220. package/src/directives/v-c-tooltip.ts +8 -12
  221. package/src/directives/v-c-visible.ts +1 -1
  222. package/src/index.ts +8 -29
  223. package/src/utils/getUID.ts +9 -0
  224. package/src/utils/index.ts +4 -1
  225. package/src/utils/isObjectInArray.ts +14 -0
  226. package/src/utils/isRTL.ts +13 -0
@@ -1,18 +1,27 @@
1
- import { defineComponent, h, PropType, provide, ref, watch } from 'vue'
1
+ import { computed, defineComponent, h, onBeforeUnmount, PropType, provide, ref, watch } from 'vue'
2
+
3
+ import { createPopper, Instance } from '@popperjs/core'
2
4
 
3
5
  import { CFormControlWrapper } from './../form/CFormControlWrapper'
4
- import { CPicker } from '../picker'
5
6
 
6
7
  import { CMultiSelectNativeSelect } from './CMultiSelectNativeSelect'
7
8
  import { CMultiSelectOptions } from './CMultiSelectOptions'
8
9
  import { CMultiSelectSelection } from './CMultiSelectSelection'
9
10
 
10
- import { filterOptionsList, flattenArray, selectOptions } from './utils'
11
- import type { Option, SelectedOption } from './types'
11
+ import { isRTL } from '../../utils'
12
+
13
+ import { createOption, filterOptionsList, flattenOptionsArray, selectOptions } from './utils'
14
+ import type { Option, OptionsGroup, SelectedOption } from './types'
12
15
 
13
16
  const CMultiSelect = defineComponent({
14
17
  name: 'CMultiSelect',
15
18
  props: {
19
+ /**
20
+ * Allow users to create options if they are not in the list of options.
21
+ *
22
+ * @since 4.9.0-next.0
23
+ */
24
+ allowCreateOptions: Boolean,
16
25
  /**
17
26
  * Enables selection cleaner element.
18
27
  *
@@ -22,43 +31,38 @@ const CMultiSelect = defineComponent({
22
31
  type: Boolean,
23
32
  default: true,
24
33
  },
34
+ /**
35
+ * Clear current search on selecting an item.
36
+ *
37
+ * @since 4.9.0-next.0
38
+ */
39
+ clearSearchOnSelect: Boolean,
25
40
  /**
26
41
  * Toggle the disabled state for the component.
27
42
  */
28
- disabled: {
29
- type: Boolean,
30
- default: false,
31
- },
43
+ disabled: Boolean,
32
44
  /**
33
45
  * Provide valuable, actionable feedback.
34
46
  *
35
47
  * @since 4.6.0
36
48
  */
37
- feedback: {
38
- type: String,
39
- },
49
+ feedback: String,
40
50
  /**
41
51
  * Provide valuable, actionable feedback.
42
52
  *
43
53
  * @since 4.6.0
44
54
  */
45
- feedbackInvalid: {
46
- type: String,
47
- },
55
+ feedbackInvalid: String,
48
56
  /**
49
57
  * Provide valuable, actionable invalid feedback when using standard HTML form validation which applied two CSS pseudo-classes, `:invalid` and `:valid`.
50
58
  *
51
59
  * @since 4.6.0
52
60
  */
53
- feedbackValid: {
54
- type: String,
55
- },
61
+ feedbackValid: String,
56
62
  /**
57
63
  * The id global attribute defines an identifier (ID) that must be unique in the whole document.
58
64
  */
59
- id: {
60
- type: String,
61
- },
65
+ id: String,
62
66
  /**
63
67
  * Set component validation state to invalid.
64
68
  *
@@ -70,9 +74,13 @@ const CMultiSelect = defineComponent({
70
74
  *
71
75
  * @since 4.6.0
72
76
  */
73
- label: {
74
- type: String,
75
- },
77
+ label: String,
78
+ /**
79
+ * When set, the options list will have a loading style: loading spinner and reduced opacity.
80
+ *
81
+ * @since 4.9.0-next.0
82
+ */
83
+ loading: Boolean,
76
84
  /**
77
85
  * It specifies that multiple options can be selected at once.
78
86
  *
@@ -86,7 +94,7 @@ const CMultiSelect = defineComponent({
86
94
  * List of option elements.
87
95
  */
88
96
  options: {
89
- type: Array as PropType<Option[]>,
97
+ type: Array as PropType<(Option | OptionsGroup)[]>,
90
98
  default: () => [],
91
99
  },
92
100
  /**
@@ -120,6 +128,10 @@ const CMultiSelect = defineComponent({
120
128
  type: String,
121
129
  default: 'Select...',
122
130
  },
131
+ /**
132
+ * When it is present, it indicates that the user must choose a value before submitting the form.
133
+ */
134
+ required: Boolean,
123
135
  /**
124
136
  * Enables search input element.
125
137
  */
@@ -199,9 +211,7 @@ const CMultiSelect = defineComponent({
199
211
  *
200
212
  * @since 4.6.0
201
213
  */
202
- text: {
203
- type: String,
204
- },
214
+ text: String,
205
215
  /**
206
216
  * Display validation feedback in a styled tooltip.
207
217
  *
@@ -225,10 +235,7 @@ const CMultiSelect = defineComponent({
225
235
  *
226
236
  * @default false
227
237
  */
228
- visible: {
229
- type: Boolean,
230
- default: false,
231
- },
238
+ visible: Boolean,
232
239
  /**
233
240
  *
234
241
  * Amount of visible items when virtualScroller is set to `true`.
@@ -251,41 +258,66 @@ const CMultiSelect = defineComponent({
251
258
  * @since 4.7.0
252
259
  */
253
260
  'filterChange',
261
+ /**
262
+ * The callback is fired when the Multi Select component requests to be hidden.
263
+ */
264
+ 'hide',
265
+ /**
266
+ * The callback is fired when the Multi Select component requests to be shown.
267
+ */
268
+ 'show',
254
269
  ],
255
- setup(props, { attrs, emit }) {
270
+ setup(props, { attrs, emit, slots }) {
271
+ const multiSelectRef = ref<HTMLDivElement>()
272
+ const dropdownRef = ref<HTMLDivElement>()
256
273
  const nativeSelectRef = ref<HTMLSelectElement>()
257
- const options = ref<Option[]>(props.options)
258
- const search = ref('')
274
+ const togglerRef = ref<HTMLDivElement>()
259
275
  const searchRef = ref<HTMLInputElement>()
276
+
277
+ const options = ref<(Option | OptionsGroup)[]>(props.options)
278
+ const popper = ref<Instance>()
279
+ const searchValue = ref('')
260
280
  const selected = ref<SelectedOption[]>([])
261
- const visible = ref<Boolean>(props.visible)
281
+ const userOptions = ref<Option[]>([])
282
+ const visible = ref<boolean>(props.visible)
262
283
 
263
284
  provide('nativeSelectRef', nativeSelectRef)
264
285
 
286
+ const filteredOptions = computed(() =>
287
+ flattenOptionsArray(
288
+ props.search === 'external'
289
+ ? [...options.value, ...filterOptionsList(searchValue.value, userOptions.value)]
290
+ : filterOptionsList(searchValue.value, [...options.value, ...userOptions.value]),
291
+ true,
292
+ ),
293
+ )
294
+
295
+ const flattenedOptions = computed(() => flattenOptionsArray(props.options))
296
+
297
+ const userOption = computed(() => {
298
+ if (
299
+ props.allowCreateOptions &&
300
+ filteredOptions.value.some(
301
+ (option) => option.text && option.text.toLowerCase() === searchValue.value.toLowerCase(),
302
+ )
303
+ ) {
304
+ return false
305
+ }
306
+
307
+ return searchRef.value && createOption(String(searchValue.value), flattenedOptions.value)
308
+ })
309
+
265
310
  watch(
266
311
  () => props.options,
267
312
  (newValue, oldValue) => {
268
313
  if (JSON.stringify(newValue) !== JSON.stringify(oldValue)) {
269
314
  options.value = newValue
270
- const _selected =
271
- newValue &&
272
- flattenArray(newValue).filter((option: Option) => {
273
- if (option.selected) {
274
- return option
275
- }
276
-
277
- return
278
- })
279
-
280
- const deselected =
281
- newValue &&
282
- flattenArray(newValue).filter((option: Option) => {
283
- if (option.selected === false) {
284
- return option
285
- }
286
-
287
- return
288
- })
315
+ const _selected = flattenedOptions.value.filter(
316
+ (option: Option | OptionsGroup) => option.selected === true,
317
+ )
318
+ const deselected = flattenedOptions.value.filter(
319
+ (option: Option | OptionsGroup) => option.selected === false,
320
+ ) as Option[]
289
321
 
290
322
  if (_selected) {
291
323
  selected.value = selectOptions(_selected, selected.value, deselected)
@@ -298,17 +330,121 @@ const CMultiSelect = defineComponent({
298
330
  watch(selected, () => {
299
331
  nativeSelectRef.value &&
300
332
  nativeSelectRef.value.dispatchEvent(new Event('change', { bubbles: true }))
333
+
334
+ if (popper.value) {
335
+ popper.value.update()
336
+ }
301
337
  })
302
338
 
339
+ watch(visible, () => {
340
+ if (visible.value) {
341
+ emit('show')
342
+
343
+ window.addEventListener('mouseup', handleMouseUp)
344
+ window.addEventListener('keyup', handleKeyUp)
345
+
346
+ initPopper()
347
+
348
+ // TODO: find better solution
349
+ setTimeout(() => {
350
+ searchRef.value && searchRef.value.focus()
351
+ }, 100)
352
+
353
+ return
354
+ }
355
+
356
+ emit('hide')
357
+
358
+ window.removeEventListener('mouseup', handleMouseUp)
359
+ window.removeEventListener('keyup', handleKeyUp)
360
+
361
+ destroyPopper()
362
+ })
363
+
364
+ onBeforeUnmount(() => {
365
+ window.removeEventListener('mouseup', handleMouseUp)
366
+ window.removeEventListener('keyup', handleKeyUp)
367
+ })
368
+
369
+ const initPopper = () => {
370
+ if (togglerRef.value && dropdownRef.value) {
371
+ popper.value = createPopper(togglerRef.value, dropdownRef.value, {
372
+ placement: isRTL() ? 'bottom-end' : 'bottom-start',
373
+ modifiers: [
374
+ {
375
+ name: 'preventOverflow',
376
+ options: {
377
+ boundary: 'clippingParents',
378
+ },
379
+ },
380
+ {
381
+ name: 'offset',
382
+ options: {
383
+ offset: [0, 2],
384
+ },
385
+ },
386
+ ],
387
+ })
388
+ }
389
+ }
390
+
391
+ const destroyPopper = () => {
392
+ if (popper.value) {
393
+ popper.value.destroy()
394
+ }
395
+
396
+ popper.value = undefined
397
+ }
398
+
399
+ const handleKeyUp = (event: KeyboardEvent) => {
400
+ if (event.key === 'Escape') {
401
+ visible.value = false
402
+ }
403
+ }
404
+
405
+ const handleMouseUp = (event: Event) => {
406
+ if (multiSelectRef.value && multiSelectRef.value.contains(event.target as HTMLElement)) {
407
+ return
408
+ }
409
+
410
+ visible.value = false
411
+ }
412
+
303
413
  const handleSearchChange = (event: InputEvent) => {
304
414
  const target = event.target as HTMLInputElement
305
- search.value = target.value.toLowerCase()
415
+ searchValue.value = target.value.toLowerCase()
306
416
 
307
417
  emit('filterChange', target.value)
308
418
  }
309
419
 
310
420
  const handleSearchKeyDown = (event: KeyboardEvent) => {
311
- if (search.value.length) {
421
+ if (event.key === 'Enter' && searchValue.value && props.allowCreateOptions) {
422
+ event.preventDefault()
423
+
424
+ if (!userOption.value) {
425
+ selected.value = [
426
+ ...selected.value,
427
+ filteredOptions.value.find(
428
+ (option) => String(option.text).toLowerCase() === searchValue.value.toLowerCase(),
429
+ ) as Option,
430
+ ]
431
+ }
432
+
433
+ if (userOption.value) {
434
+ selected.value = [...selected.value, ...userOption.value]
435
+ userOptions.value = [...userOptions.value, ...userOption.value]
436
+ }
437
+
438
+ searchValue.value = ''
439
+
440
+ if (searchRef.value) {
441
+ searchRef.value.value = ''
442
+ }
443
+
444
+ return
445
+ }
446
+
447
+ if (searchValue.value.length > 0) {
312
448
  return
313
449
  }
314
450
 
@@ -324,7 +460,7 @@ const CMultiSelect = defineComponent({
324
460
  if (!props.multiple) {
325
461
  selected.value = [{ value: option.value, text: option.text }] as SelectedOption[]
326
462
  visible.value = false
327
- search.value = ''
463
+
328
464
  if (searchRef.value) {
329
465
  searchRef.value.value = ''
330
466
  }
@@ -332,6 +468,18 @@ const CMultiSelect = defineComponent({
332
468
  return
333
469
  }
334
470
 
471
+ if (option.custom && !userOptions.value.some((_option) => _option.value === option.value)) {
472
+ userOptions.value = [...userOptions.value, option]
473
+ }
474
+
475
+ if (props.clearSearchOnSelect || option.custom) {
476
+ searchValue.value = ''
477
+ if (searchRef.value) {
478
+ searchRef.value.value = ''
479
+ searchRef.value.focus()
480
+ }
481
+ }
482
+
335
483
  if (selected.value.some((_option) => _option.value === option.value)) {
336
484
  selected.value = selected.value.filter((_option) => _option.value !== option.value)
337
485
  } else {
@@ -344,7 +492,10 @@ const CMultiSelect = defineComponent({
344
492
 
345
493
  const handleSelectAll = () => {
346
494
  selected.value = selectOptions(
347
- flattenArray(options.value).filter((option: Option) => !option.disabled),
495
+ [
496
+ ...flattenedOptions.value.filter((option: Option | OptionsGroup) => !option.disabled),
497
+ ...userOptions.value,
498
+ ],
348
499
  selected.value,
349
500
  )
350
501
  }
@@ -355,11 +506,13 @@ const CMultiSelect = defineComponent({
355
506
 
356
507
  return () => [
357
508
  h(CMultiSelectNativeSelect, {
509
+ id: props.id,
358
510
  multiple: props.multiple,
359
- options: options.value,
511
+ options: selected.value,
512
+ required: props.required,
360
513
  value: props.multiple
361
- ? selected.value.map((option: Option) => option.value.toString())
362
- : selected.value.map((option: Option) => option.value)[0],
514
+ ? selected.value.map((option: SelectedOption) => option.value.toString())
515
+ : selected.value.map((option: SelectedOption) => option.value)[0],
363
516
  onChange: () => emit('change', selected.value),
364
517
  }),
365
518
  h(
@@ -379,102 +532,142 @@ const CMultiSelect = defineComponent({
379
532
  {
380
533
  default: () =>
381
534
  h(
382
- CPicker,
535
+ 'div',
383
536
  {
384
537
  class: [
385
538
  'form-multi-select',
386
539
  {
387
- 'form-multi-select-with-cleaner': props.cleaner,
388
540
  disabled: props.disabled,
389
541
  [`form-multi-select-${props.size}`]: props.size,
390
- 'form-multi-select-selection-tags':
391
- props.multiple && props.selectionType === 'tags',
392
- show: visible.value,
393
542
  'is-invalid': props.invalid,
394
543
  'is-valid': props.valid,
544
+ show: visible.value,
395
545
  },
396
546
  ],
397
- disabled: props.disabled,
547
+ 'aria-expanded': visible.value,
398
548
  id: props.id,
399
- onHide: () => {
400
- visible.value = false
401
- },
402
- onShow: () => {
403
- props.search && searchRef.value && searchRef.value.focus()
404
- visible.value = true
405
- },
406
- visible: visible.value,
549
+ ref: multiSelectRef,
407
550
  },
408
551
  {
409
- toggler: () =>
410
- h('div', {}, [
411
- h(CMultiSelectSelection, {
412
- multiple: props.multiple,
413
- onRemove: (option: Option) => !props.disabled && handleOptionClick(option),
414
- search: props.search,
415
- selected: selected.value,
416
- selectionType: props.selectionType,
417
- selectionTypeCounterText: props.selectionTypeCounterText,
418
- }),
419
- props.multiple &&
420
- props.cleaner &&
421
- selected.value.length > 0 &&
422
- !props.disabled &&
423
- h('button', {
424
- type: 'button',
425
- class: 'form-multi-select-selection-cleaner',
426
- onClick: () => handleDeselectAll(),
427
- }),
428
- props.search &&
429
- h('input', {
430
- type: 'text',
431
- class: 'form-multi-select-search',
432
- autocomplete: 'off',
433
- ...(selected.value.length === 0 && { placeholder: props.placeholder }),
434
- ...(selected.value.length &&
435
- props.selectionType === 'counter' && {
436
- placeholder: `${selected.value.length} ${props.selectionTypeCounterText}`,
437
- }),
438
- ...(selected.value.length &&
439
- !props.multiple && {
440
- placeholder: selected.value.map((option) => option.text)[0],
441
- }),
442
- disabled: props.disabled,
443
- onInput: (event: InputEvent) => handleSearchChange(event),
444
- onKeydown: (event: KeyboardEvent) => handleSearchKeyDown(event),
445
- ...(props.multiple &&
446
- selected.value.length &&
447
- props.selectionType !== 'counter' && { size: search.value.length + 2 }),
448
- ref: searchRef,
449
- }),
450
- ]),
451
- default: () =>
452
- visible.value && [
453
- props.multiple &&
454
- props.selectAll &&
455
- h(
456
- 'button',
457
- {
458
- class: 'form-multi-select-all',
459
- onClick: () => handleSelectAll(),
460
- type: 'button',
461
- },
462
- props.selectAllLabel,
463
- ),
464
- h(CMultiSelectOptions, {
465
- onOptionClick: (option: Option) => handleOptionClick(option),
466
- options:
467
- props.search === 'external'
468
- ? options.value
469
- : filterOptionsList(search.value, options.value),
470
- optionsMaxHeight: props.optionsMaxHeight,
471
- optionsStyle: props.optionsStyle,
472
- searchNoResultsLabel: props.searchNoResultsLabel,
473
- selected: selected.value,
474
- virtualScroller: props.virtualScroller,
475
- visibleItems: props.visibleItems,
476
- }),
477
- ],
552
+ default: () => [
553
+ h(
554
+ 'div',
555
+ {
556
+ class: 'form-multi-select-input-group',
557
+ onClick: () => {
558
+ visible.value = true
559
+ },
560
+ ref: togglerRef,
561
+ },
562
+ {
563
+ default: () => [
564
+ h(
565
+ CMultiSelectSelection,
566
+ {
567
+ multiple: props.multiple,
568
+ placeholder: props.placeholder,
569
+ onRemove: (option: Option) =>
570
+ !props.disabled && handleOptionClick(option),
571
+ search: props.search,
572
+ selected: selected.value,
573
+ selectionType: props.selectionType,
574
+ selectionTypeCounterText: props.selectionTypeCounterText,
575
+ },
576
+ {
577
+ default: () =>
578
+ props.search &&
579
+ h('input', {
580
+ type: 'text',
581
+ class: 'form-multi-select-search',
582
+ disabled: props.disabled,
583
+ autocomplete: 'off',
584
+ onInput: (event: InputEvent) => handleSearchChange(event),
585
+ onKeydown: (event: KeyboardEvent) => handleSearchKeyDown(event),
586
+ ...(selected.value.length === 0 && {
587
+ placeholder: props.placeholder,
588
+ }),
589
+ ...(selected.value.length > 0 &&
590
+ props.selectionType === 'counter' && {
591
+ placeholder: `${selected.value.length} ${props.selectionTypeCounterText}`,
592
+ }),
593
+ ...(selected.value.length > 0 &&
594
+ !props.multiple && {
595
+ placeholder: selected.value.map((option) => option.text)[0],
596
+ }),
597
+
598
+ ...(props.multiple &&
599
+ selected.value.length > 0 &&
600
+ props.selectionType !== 'counter' && {
601
+ size: searchValue.value.length + 2,
602
+ }),
603
+ ref: searchRef,
604
+ }),
605
+ },
606
+ ),
607
+ h(
608
+ 'div',
609
+ { class: 'form-multi-select-buttons' },
610
+ {
611
+ default: () => [
612
+ h('button', {
613
+ class: 'form-multi-select-cleaner',
614
+ onClick: () => handleDeselectAll(),
615
+ type: 'button',
616
+ }),
617
+ h('button', {
618
+ class: 'form-multi-select-indicator',
619
+ onClick: (event: Event) => {
620
+ event.preventDefault()
621
+ event.stopPropagation()
622
+ visible.value = !visible.value
623
+ },
624
+ type: 'button',
625
+ }),
626
+ ],
627
+ },
628
+ ),
629
+ ],
630
+ },
631
+ ),
632
+ h(
633
+ 'div',
634
+ {
635
+ class: 'form-multi-select-dropdown',
636
+ role: 'menu',
637
+ ref: dropdownRef,
638
+ },
639
+ {
640
+ default: () => [
641
+ props.multiple &&
642
+ props.selectAll &&
643
+ h(
644
+ 'button',
645
+ {
646
+ class: 'form-multi-select-all',
647
+ onClick: () => handleSelectAll(),
648
+ type: 'button',
649
+ },
650
+ props.selectAllLabel,
651
+ ),
652
+ h(CMultiSelectOptions, {
653
+ loading: props.loading,
654
+ onOptionClick: (option: Option) => handleOptionClick(option),
655
+ options:
656
+ filteredOptions.value.length === 0 && props.allowCreateOptions
657
+ ? userOption.value || []
658
+ : filteredOptions.value,
659
+ optionsMaxHeight: props.optionsMaxHeight,
660
+ optionsStyle: props.optionsStyle,
661
+ scopedSlots: slots,
662
+ searchNoResultsLabel: props.searchNoResultsLabel,
663
+ selected: selected.value,
664
+ virtualScroller: props.virtualScroller,
665
+ visibleItems: props.visibleItems,
666
+ }),
667
+ ],
668
+ },
669
+ ),
670
+ ],
478
671
  },
479
672
  ),
480
673
  },