@coreui/vue-pro 4.5.0 → 4.7.0-alpha.0
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.
- package/dist/components/Types.d.ts +5 -5
- package/dist/components/calendar/CCalendar.d.ts +41 -3
- package/dist/components/date-picker/CDatePicker.d.ts +43 -4
- package/dist/components/date-range-picker/CDateRangePicker.d.ts +191 -4
- package/dist/components/form/CFormInput.d.ts +166 -1
- package/dist/components/form/CFormSelect.d.ts +1 -1
- package/dist/components/grid/CCol.d.ts +3 -3
- package/dist/components/grid/CRow.d.ts +1 -1
- package/dist/components/index.d.ts +1 -0
- package/dist/components/multi-select/CMultiSelect.d.ts +143 -4
- package/dist/components/multi-select/CMultiSelectOptions.d.ts +11 -0
- package/dist/components/multi-select/CMultiSelectSelection.d.ts +3 -3
- package/dist/components/pagination/index.d.ts +1 -2
- package/dist/components/picker/CPicker.d.ts +1 -1
- package/dist/components/popover/CPopover.d.ts +1 -1
- package/dist/components/smart-pagination/CSmartPagination.d.ts +257 -0
- package/dist/components/smart-pagination/index.d.ts +6 -0
- package/dist/components/smart-table/CSmartTable.d.ts +6 -4
- package/dist/components/smart-table/CSmartTableFilter.d.ts +2 -2
- package/dist/components/smart-table/CSmartTableHead.d.ts +2 -2
- package/dist/components/smart-table/CSmartTableInterface.d.ts +4 -1
- package/dist/components/table/CTable.d.ts +1 -1
- package/dist/components/table/CTableCaption.d.ts +2 -8
- package/dist/components/time-picker/CTimePicker.d.ts +2 -1
- package/dist/components/tooltip/CTooltip.d.ts +1 -1
- package/dist/components/widgets/CWidgetStatsD.d.ts +1 -1
- package/dist/index.es.js +1560 -1017
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +1559 -1015
- package/dist/index.js.map +1 -1
- package/dist/utils/getNextSibling.d.ts +2 -0
- package/dist/utils/getPreviousSibling.d.ts +2 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/isVisible.d.ts +2 -0
- package/dist/utils/time.d.ts +2 -2
- package/package.json +2 -2
- package/src/components/calendar/CCalendar.ts +46 -4
- package/src/components/carousel/CCarousel.ts +1 -9
- package/src/components/date-picker/CDatePicker.ts +44 -3
- package/src/components/date-range-picker/CDateRangePicker.ts +340 -170
- package/src/components/form/CFormInput.ts +2 -0
- package/src/components/index.ts +1 -0
- package/src/components/loading-button/CLoadingButton.ts +1 -2
- package/src/components/multi-select/CMultiSelect.ts +295 -173
- package/src/components/multi-select/CMultiSelectOptions.ts +48 -10
- package/src/components/multi-select/CMultiSelectSelection.ts +1 -1
- package/src/components/pagination/index.ts +1 -3
- package/src/components/sidebar/CSidebar.ts +2 -10
- package/src/components/{pagination → smart-pagination}/CSmartPagination.ts +1 -2
- package/src/components/smart-pagination/index.ts +10 -0
- package/src/components/smart-table/CSmartTable.ts +10 -5
- package/src/components/smart-table/CSmartTableInterface.ts +4 -0
- package/src/components/table/CTableCaption.ts +0 -1
- package/src/components/time-picker/CTimePicker.ts +198 -64
- package/src/components/time-picker/CTimePickerRollCol.ts +9 -0
- package/src/utils/getNextSibling.ts +18 -0
- package/src/utils/getPreviousSibling.ts +18 -0
- package/src/utils/index.ts +5 -0
- package/src/utils/isVisible.ts +11 -0
- package/src/utils/time.ts +14 -6
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { defineComponent, h, PropType, provide, ref, watch } from 'vue'
|
|
2
2
|
|
|
3
|
+
import { CFormControlWrapper } from './../form/CFormControlWrapper'
|
|
3
4
|
import { CPicker } from '../picker'
|
|
4
5
|
|
|
5
6
|
import { CMultiSelectNativeSelect } from './CMultiSelectNativeSelect'
|
|
@@ -15,6 +16,18 @@ export interface Option {
|
|
|
15
16
|
value: number | string
|
|
16
17
|
}
|
|
17
18
|
|
|
19
|
+
export interface SelectedOption {
|
|
20
|
+
disabled?: boolean
|
|
21
|
+
text: string
|
|
22
|
+
value: number | string
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const flattenArray = (options: Option[]): Option[] => {
|
|
26
|
+
return options.reduce((acc: Option[], val: Option) => {
|
|
27
|
+
return acc.concat(Array.isArray(val.options) ? flattenArray(val.options) : val)
|
|
28
|
+
}, [])
|
|
29
|
+
}
|
|
30
|
+
|
|
18
31
|
const CMultiSelect = defineComponent({
|
|
19
32
|
name: 'CMultiSelect',
|
|
20
33
|
props: {
|
|
@@ -36,6 +49,50 @@ const CMultiSelect = defineComponent({
|
|
|
36
49
|
required: false,
|
|
37
50
|
default: false,
|
|
38
51
|
},
|
|
52
|
+
/**
|
|
53
|
+
* Provide valuable, actionable feedback.
|
|
54
|
+
*
|
|
55
|
+
* @since 4.6.0
|
|
56
|
+
*/
|
|
57
|
+
feedback: {
|
|
58
|
+
type: String,
|
|
59
|
+
},
|
|
60
|
+
/**
|
|
61
|
+
* Provide valuable, actionable feedback.
|
|
62
|
+
*
|
|
63
|
+
* @since 4.6.0
|
|
64
|
+
*/
|
|
65
|
+
feedbackInvalid: {
|
|
66
|
+
type: String,
|
|
67
|
+
},
|
|
68
|
+
/**
|
|
69
|
+
* Provide valuable, actionable invalid feedback when using standard HTML form validation which applied two CSS pseudo-classes, `:invalid` and `:valid`.
|
|
70
|
+
*
|
|
71
|
+
* @since 4.6.0
|
|
72
|
+
*/
|
|
73
|
+
feedbackValid: {
|
|
74
|
+
type: String,
|
|
75
|
+
},
|
|
76
|
+
/**
|
|
77
|
+
* The id global attribute defines an identifier (ID) that must be unique in the whole document.
|
|
78
|
+
*/
|
|
79
|
+
id: {
|
|
80
|
+
type: String,
|
|
81
|
+
},
|
|
82
|
+
/**
|
|
83
|
+
* Set component validation state to invalid.
|
|
84
|
+
*
|
|
85
|
+
* @since 4.6.0
|
|
86
|
+
*/
|
|
87
|
+
invalid: Boolean,
|
|
88
|
+
/**
|
|
89
|
+
* Add a caption for a component.
|
|
90
|
+
*
|
|
91
|
+
* @since 4.6.0
|
|
92
|
+
*/
|
|
93
|
+
label: {
|
|
94
|
+
type: String,
|
|
95
|
+
},
|
|
39
96
|
/**
|
|
40
97
|
* It specifies that multiple options can be selected at once.
|
|
41
98
|
*
|
|
@@ -92,9 +149,18 @@ const CMultiSelect = defineComponent({
|
|
|
92
149
|
* Enables search input element.
|
|
93
150
|
*/
|
|
94
151
|
search: {
|
|
95
|
-
type: Boolean,
|
|
152
|
+
type: [Boolean, String],
|
|
96
153
|
default: true,
|
|
97
154
|
required: false,
|
|
155
|
+
validator: (value: boolean | string) => {
|
|
156
|
+
if (typeof value == 'string') {
|
|
157
|
+
return ['external'].includes(value)
|
|
158
|
+
}
|
|
159
|
+
if (typeof value == 'boolean') {
|
|
160
|
+
return true
|
|
161
|
+
}
|
|
162
|
+
return false
|
|
163
|
+
},
|
|
98
164
|
},
|
|
99
165
|
/**
|
|
100
166
|
* Sets the label for no results when filtering.
|
|
@@ -160,6 +226,26 @@ const CMultiSelect = defineComponent({
|
|
|
160
226
|
return ['sm', 'lg'].includes(value)
|
|
161
227
|
},
|
|
162
228
|
},
|
|
229
|
+
/**
|
|
230
|
+
* Add helper text to the component.
|
|
231
|
+
*
|
|
232
|
+
* @since 4.6.0
|
|
233
|
+
*/
|
|
234
|
+
text: {
|
|
235
|
+
type: String,
|
|
236
|
+
},
|
|
237
|
+
/**
|
|
238
|
+
* Display validation feedback in a styled tooltip.
|
|
239
|
+
*
|
|
240
|
+
* @since 4.6.0
|
|
241
|
+
*/
|
|
242
|
+
tooltipFeedback: Boolean,
|
|
243
|
+
/**
|
|
244
|
+
* Set component validation state to valid.
|
|
245
|
+
*
|
|
246
|
+
* @since 4.6.0
|
|
247
|
+
*/
|
|
248
|
+
valid: Boolean,
|
|
163
249
|
/**
|
|
164
250
|
* Toggle the visibility of multi select dropdown.
|
|
165
251
|
*
|
|
@@ -176,70 +262,83 @@ const CMultiSelect = defineComponent({
|
|
|
176
262
|
* Execute a function when a user changes the selected option. [docs]
|
|
177
263
|
*/
|
|
178
264
|
'change',
|
|
265
|
+
/**
|
|
266
|
+
* Execute a function when the filter value changed.
|
|
267
|
+
*
|
|
268
|
+
* @since 4.7.0
|
|
269
|
+
*/
|
|
270
|
+
'filterChange',
|
|
179
271
|
],
|
|
180
|
-
setup(props, { emit }) {
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
272
|
+
setup(props, { attrs, emit }) {
|
|
273
|
+
const nativeSelectRef = ref<HTMLSelectElement>()
|
|
274
|
+
provide('nativeSelectRef', nativeSelectRef)
|
|
275
|
+
const searchRef = ref<HTMLInputElement>()
|
|
276
|
+
|
|
277
|
+
const options = ref<Option[]>(props.options)
|
|
278
|
+
const search = ref('')
|
|
279
|
+
const selected = ref<SelectedOption[]>([])
|
|
280
|
+
const visible = ref<Boolean>(props.visible)
|
|
186
281
|
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
282
|
+
const selectOptions = (options: Option[], deselected?: Option[]) => {
|
|
283
|
+
let _selected = [...selected.value, ...options]
|
|
284
|
+
|
|
285
|
+
if (deselected) {
|
|
286
|
+
_selected = _selected.filter(
|
|
287
|
+
(selectedOption) =>
|
|
288
|
+
!deselected.some((deselectedOption) => deselectedOption.value === selectedOption.value),
|
|
289
|
+
)
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const deduplicated = _selected.reduce((unique: Option[], option) => {
|
|
293
|
+
if (!unique.some((obj) => obj.value === option.value)) {
|
|
294
|
+
unique.push({
|
|
295
|
+
value: option.value,
|
|
296
|
+
text: option.text,
|
|
297
|
+
...(option.disabled && { disabled: option.disabled }),
|
|
298
|
+
})
|
|
191
299
|
}
|
|
192
|
-
return
|
|
193
|
-
})
|
|
300
|
+
return unique
|
|
301
|
+
}, []) as SelectedOption[]
|
|
302
|
+
|
|
303
|
+
selected.value = deduplicated
|
|
194
304
|
}
|
|
195
305
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
306
|
+
watch(
|
|
307
|
+
() => props.options,
|
|
308
|
+
(newValue, oldValue) => {
|
|
309
|
+
if (JSON.stringify(newValue) !== JSON.stringify(oldValue)) {
|
|
310
|
+
options.value = newValue
|
|
311
|
+
const _selected =
|
|
312
|
+
newValue &&
|
|
313
|
+
flattenArray(newValue).filter((option: Option) => {
|
|
314
|
+
if (option.selected) {
|
|
315
|
+
return option
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
return
|
|
209
319
|
})
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
320
|
+
|
|
321
|
+
const deselected =
|
|
322
|
+
newValue &&
|
|
323
|
+
flattenArray(newValue).filter((option: Option) => {
|
|
324
|
+
if (option.selected === false) {
|
|
325
|
+
return option
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
return
|
|
217
329
|
})
|
|
218
|
-
}
|
|
219
330
|
|
|
220
|
-
|
|
221
|
-
options: Option[],
|
|
222
|
-
selected: boolean,
|
|
223
|
-
counter: number = count.value,
|
|
224
|
-
): Option[] => {
|
|
225
|
-
return options.map((option: Option) => {
|
|
226
|
-
!option.selected && counter++
|
|
227
|
-
count.value = counter
|
|
228
|
-
if (option.options) {
|
|
229
|
-
return {
|
|
230
|
-
...option,
|
|
231
|
-
options: toggleAllOptions(option.options, selected, counter),
|
|
232
|
-
}
|
|
331
|
+
_selected && selectOptions(_selected, deselected)
|
|
233
332
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
}
|
|
333
|
+
},
|
|
334
|
+
)
|
|
335
|
+
|
|
336
|
+
watch(selected, () => {
|
|
337
|
+
nativeSelectRef.value &&
|
|
338
|
+
nativeSelectRef.value.dispatchEvent(new Event('change', { bubbles: true }))
|
|
339
|
+
})
|
|
241
340
|
|
|
242
|
-
const filterOptionsList = (search: string, _options
|
|
341
|
+
const filterOptionsList = (search: string, _options: Option[]) => {
|
|
243
342
|
return search.length
|
|
244
343
|
? _options &&
|
|
245
344
|
_options.reduce((acc: Option[], val: Option) => {
|
|
@@ -262,76 +361,64 @@ const CMultiSelect = defineComponent({
|
|
|
262
361
|
: options.value
|
|
263
362
|
}
|
|
264
363
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
const visible = ref<Boolean>(props.visible)
|
|
273
|
-
|
|
274
|
-
const selected = ref<Option[]>(getSelectedOptions(props.options))
|
|
275
|
-
const count = ref<number>(0)
|
|
276
|
-
|
|
277
|
-
watch(
|
|
278
|
-
() => props.options,
|
|
279
|
-
(newValue, oldValue) => {
|
|
280
|
-
if (JSON.stringify(newValue) !== JSON.stringify(oldValue)) options.value = newValue
|
|
281
|
-
},
|
|
282
|
-
)
|
|
364
|
+
// watch(
|
|
365
|
+
// () => props.options,
|
|
366
|
+
// (newValue, oldValue) => {
|
|
367
|
+
// console.log(props.options)
|
|
368
|
+
// if (JSON.stringify(newValue) !== JSON.stringify(oldValue)) options.value = newValue
|
|
369
|
+
// },
|
|
370
|
+
// )
|
|
283
371
|
|
|
284
|
-
watch(options, () => {
|
|
285
|
-
const _selected = options.value && getSelectedOptions(options.value)
|
|
286
372
|
|
|
287
|
-
_selected.sort((a: Option, b: Option) => {
|
|
288
|
-
if (typeof a.order === 'undefined') {
|
|
289
|
-
return -1
|
|
290
|
-
}
|
|
291
|
-
if (b.order && a.order > b.order) return 1
|
|
292
|
-
if (b.order && a.order < b.order) return -1
|
|
293
|
-
return 0
|
|
294
|
-
})
|
|
295
|
-
|
|
296
|
-
selected.value = _selected
|
|
297
|
-
})
|
|
298
|
-
|
|
299
|
-
watch([options, search], () => {
|
|
300
|
-
vOptions.value = filterOptionsList(search.value, options.value)
|
|
301
|
-
})
|
|
302
|
-
|
|
303
|
-
watch(selected, () => {
|
|
304
|
-
nativeSelectRef.value &&
|
|
305
|
-
nativeSelectRef.value.dispatchEvent(new Event('change', { bubbles: true }))
|
|
306
|
-
})
|
|
307
373
|
|
|
308
374
|
const handleSearchChange = (event: InputEvent) => {
|
|
309
375
|
const target = event.target as HTMLInputElement
|
|
310
376
|
search.value = target.value.toLowerCase()
|
|
377
|
+
|
|
378
|
+
emit('filterChange', target.value)
|
|
311
379
|
}
|
|
312
380
|
|
|
313
381
|
const handleSearchKeyDown = (event: KeyboardEvent) => {
|
|
314
|
-
if (search.value.length)
|
|
382
|
+
if (search.value.length) {
|
|
383
|
+
return
|
|
384
|
+
}
|
|
385
|
+
|
|
315
386
|
if (event.key === 'Backspace' || event.key === 'Delete') {
|
|
316
387
|
const last = selected.value.filter((option: Option) => !option.disabled).pop()
|
|
317
|
-
|
|
318
388
|
if (last) {
|
|
319
389
|
selected.value = selected.value.filter((option: Option) => option.value !== last.value)
|
|
320
|
-
options.value = updateOptions(last.value)
|
|
321
390
|
}
|
|
322
391
|
}
|
|
323
392
|
}
|
|
324
393
|
|
|
325
394
|
const handleOptionClick = (option: Option) => {
|
|
326
|
-
|
|
395
|
+
if (!props.multiple) {
|
|
396
|
+
selected.value = [{ value: option.value, text: option.text }] as SelectedOption[]
|
|
397
|
+
visible.value = false
|
|
398
|
+
search.value = ''
|
|
399
|
+
if (searchRef.value) {
|
|
400
|
+
searchRef.value.value = ''
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
return
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
if (selected.value.some((_option) => _option.value === option.value)) {
|
|
407
|
+
selected.value = selected.value.filter((_option) => _option.value !== option.value)
|
|
408
|
+
} else {
|
|
409
|
+
selected.value = [
|
|
410
|
+
...selected.value,
|
|
411
|
+
{ value: option.value, text: option.text },
|
|
412
|
+
] as SelectedOption[]
|
|
413
|
+
}
|
|
327
414
|
}
|
|
328
415
|
|
|
329
416
|
const handleSelectAll = () => {
|
|
330
|
-
options.value
|
|
417
|
+
selectOptions(flattenArray(options.value).filter((option: Option) => !option.disabled))
|
|
331
418
|
}
|
|
332
419
|
|
|
333
420
|
const handleDeselectAll = () => {
|
|
334
|
-
|
|
421
|
+
selected.value = selected.value.filter((option) => option.disabled)
|
|
335
422
|
}
|
|
336
423
|
|
|
337
424
|
return () => [
|
|
@@ -344,83 +431,118 @@ const CMultiSelect = defineComponent({
|
|
|
344
431
|
onChange: () => emit('change', selected.value),
|
|
345
432
|
}),
|
|
346
433
|
h(
|
|
347
|
-
|
|
434
|
+
CFormControlWrapper,
|
|
348
435
|
{
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
disabled: props.disabled,
|
|
360
|
-
onShow: () => {
|
|
361
|
-
props.search && searchRef.value && searchRef.value.focus()
|
|
362
|
-
},
|
|
436
|
+
describedby: attrs['aria-describedby'],
|
|
437
|
+
feedback: props.feedback,
|
|
438
|
+
feedbackInvalid: props.feedbackInvalid,
|
|
439
|
+
feedbackValid: props.feedbackValid,
|
|
440
|
+
id: props.id,
|
|
441
|
+
invalid: props.invalid,
|
|
442
|
+
label: props.label,
|
|
443
|
+
text: props.text,
|
|
444
|
+
tooltipFeedback: props.tooltipFeedback,
|
|
445
|
+
valid: props.valid,
|
|
363
446
|
},
|
|
364
447
|
{
|
|
365
|
-
|
|
366
|
-
h(
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
448
|
+
default: () =>
|
|
449
|
+
h(
|
|
450
|
+
CPicker,
|
|
451
|
+
{
|
|
452
|
+
class: [
|
|
453
|
+
'form-multi-select',
|
|
454
|
+
{
|
|
455
|
+
'form-multi-select-with-cleaner': props.cleaner,
|
|
456
|
+
disabled: props.disabled,
|
|
457
|
+
[`form-multi-select-${props.size}`]: props.size,
|
|
458
|
+
'form-multi-select-selection-tags':
|
|
459
|
+
props.multiple && props.selectionType === 'tags',
|
|
460
|
+
show: visible.value,
|
|
461
|
+
'is-invalid': props.invalid,
|
|
462
|
+
'is-valid': props.valid,
|
|
463
|
+
},
|
|
464
|
+
],
|
|
465
|
+
disabled: props.disabled,
|
|
466
|
+
id: props.id,
|
|
467
|
+
onHide: () => {
|
|
468
|
+
visible.value = false
|
|
469
|
+
},
|
|
470
|
+
onShow: () => {
|
|
471
|
+
props.search && searchRef.value && searchRef.value.focus()
|
|
472
|
+
visible.value = true
|
|
473
|
+
},
|
|
474
|
+
visible: visible.value,
|
|
475
|
+
},
|
|
476
|
+
{
|
|
477
|
+
toggler: () =>
|
|
478
|
+
h('div', {}, [
|
|
479
|
+
h(CMultiSelectSelection, {
|
|
480
|
+
multiple: props.multiple,
|
|
481
|
+
onRemove: (option: Option) => !props.disabled && handleOptionClick(option),
|
|
482
|
+
search: props.search,
|
|
483
|
+
selected: selected.value,
|
|
484
|
+
selectionType: props.selectionType,
|
|
485
|
+
selectionTypeCounterText: props.selectionTypeCounterText,
|
|
393
486
|
}),
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
487
|
+
props.multiple &&
|
|
488
|
+
props.cleaner &&
|
|
489
|
+
selected.value.length > 0 &&
|
|
490
|
+
!props.disabled &&
|
|
491
|
+
h('button', {
|
|
492
|
+
type: 'button',
|
|
493
|
+
class: 'form-multi-select-selection-cleaner',
|
|
494
|
+
onClick: () => handleDeselectAll(),
|
|
495
|
+
}),
|
|
496
|
+
props.search &&
|
|
497
|
+
h('input', {
|
|
498
|
+
type: 'text',
|
|
499
|
+
class: 'form-multi-select-search',
|
|
500
|
+
autocomplete: 'off',
|
|
501
|
+
...(selected.value.length === 0 && { placeholder: props.placeholder }),
|
|
502
|
+
...(selected.value.length &&
|
|
503
|
+
props.selectionType === 'counter' && {
|
|
504
|
+
placeholder: `${selected.value.length} ${props.selectionTypeCounterText}`,
|
|
505
|
+
}),
|
|
506
|
+
...(selected.value.length &&
|
|
507
|
+
!props.multiple && {
|
|
508
|
+
placeholder: selected.value.map((option) => option.text)[0],
|
|
509
|
+
}),
|
|
510
|
+
disabled: props.disabled,
|
|
511
|
+
onInput: (event: InputEvent) => handleSearchChange(event),
|
|
512
|
+
onKeydown: (event: KeyboardEvent) => handleSearchKeyDown(event),
|
|
513
|
+
...(props.multiple &&
|
|
514
|
+
selected.value.length &&
|
|
515
|
+
props.selectionType !== 'counter' && { size: search.value.length + 2 }),
|
|
516
|
+
ref: searchRef,
|
|
517
|
+
}),
|
|
518
|
+
]),
|
|
519
|
+
default: () =>
|
|
520
|
+
h('div', {}, [
|
|
521
|
+
props.multiple &&
|
|
522
|
+
props.selectAll &&
|
|
523
|
+
h(
|
|
524
|
+
'button',
|
|
525
|
+
{
|
|
526
|
+
class: 'form-multi-select-all',
|
|
527
|
+
onClick: () => handleSelectAll(),
|
|
528
|
+
type: 'button',
|
|
529
|
+
},
|
|
530
|
+
props.selectAllLabel,
|
|
531
|
+
),
|
|
532
|
+
h(CMultiSelectOptions, {
|
|
533
|
+
onOptionClick: (option: Option) => handleOptionClick(option),
|
|
534
|
+
options:
|
|
535
|
+
props.search === 'external'
|
|
536
|
+
? options.value
|
|
537
|
+
: filterOptionsList(search.value, options.value),
|
|
538
|
+
optionsMaxHeight: props.optionsMaxHeight,
|
|
539
|
+
optionsStyle: props.optionsStyle,
|
|
540
|
+
searchNoResultsLabel: props.searchNoResultsLabel,
|
|
541
|
+
selected: selected.value
|
|
397
542
|
}),
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
...(props.multiple &&
|
|
402
|
-
selected.value.length &&
|
|
403
|
-
props.selectionType !== 'counter' && { size: search.value.length + 2 }),
|
|
404
|
-
ref: searchRef,
|
|
405
|
-
}),
|
|
406
|
-
]),
|
|
407
|
-
default: () =>
|
|
408
|
-
h('div', {}, [
|
|
409
|
-
props.multiple &&
|
|
410
|
-
props.selectAll &&
|
|
411
|
-
h(
|
|
412
|
-
'button',
|
|
413
|
-
{ class: 'form-multi-select-all', onClick: () => handleSelectAll() },
|
|
414
|
-
props.selectAllLabel,
|
|
415
|
-
),
|
|
416
|
-
h(CMultiSelectOptions, {
|
|
417
|
-
onOptionClick: (option: Option) => handleOptionClick(option),
|
|
418
|
-
options: vOptions.value,
|
|
419
|
-
optionsMaxHeight: props.optionsMaxHeight,
|
|
420
|
-
optionsStyle: props.optionsStyle,
|
|
421
|
-
searchNoResultsLabel: props.searchNoResultsLabel,
|
|
422
|
-
}),
|
|
423
|
-
]),
|
|
543
|
+
]),
|
|
544
|
+
},
|
|
545
|
+
),
|
|
424
546
|
},
|
|
425
547
|
),
|
|
426
548
|
]
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { defineComponent, h, PropType, VNode } from 'vue'
|
|
2
2
|
import { Option } from './CMultiSelect'
|
|
3
3
|
|
|
4
|
+
import { getNextSibling, getPreviousSibling } from './../../utils'
|
|
5
|
+
|
|
4
6
|
const CMultiSelectOptions = defineComponent({
|
|
5
7
|
name: 'CMultiSelectOptions',
|
|
6
8
|
props: {
|
|
@@ -44,20 +46,53 @@ const CMultiSelectOptions = defineComponent({
|
|
|
44
46
|
default: 'no items',
|
|
45
47
|
required: false,
|
|
46
48
|
},
|
|
49
|
+
selected: {
|
|
50
|
+
type: Array as PropType<Option[]>,
|
|
51
|
+
default: () => [],
|
|
52
|
+
required: false,
|
|
53
|
+
},
|
|
47
54
|
},
|
|
48
55
|
emits: ['optionClick'],
|
|
49
56
|
setup(props, { emit }) {
|
|
57
|
+
const handleKeyDown = (event: KeyboardEvent, option: Option) => {
|
|
58
|
+
if (event.code === 'Space' || event.key === 'Enter') {
|
|
59
|
+
event.preventDefault()
|
|
60
|
+
handleOptionClick && handleOptionClick(option)
|
|
61
|
+
return
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (event.key === 'Down' || event.key === 'ArrowDown') {
|
|
65
|
+
event.preventDefault()
|
|
66
|
+
const target = event.target as HTMLElement
|
|
67
|
+
const next = getNextSibling(target, '.form-multi-select-option')
|
|
68
|
+
if (next) {
|
|
69
|
+
;(next as HTMLElement).focus() // eslint-disable-line prettier/prettier
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (event.key === 'Up' || event.key === 'ArrowUp') {
|
|
74
|
+
event.preventDefault()
|
|
75
|
+
const target = event.target as HTMLElement
|
|
76
|
+
const prev = getPreviousSibling(target, '.form-multi-select-option')
|
|
77
|
+
if (prev) {
|
|
78
|
+
;(prev as HTMLElement).focus() // eslint-disable-line prettier/prettier
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
50
83
|
const handleOptionClick = (option: Option) => {
|
|
51
84
|
emit('optionClick', option as Option)
|
|
52
85
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
86
|
+
|
|
87
|
+
// TODO: find solution how to remove any
|
|
88
|
+
const createOptions = (options: Option[]): VNode | VNode[] | any =>
|
|
89
|
+
options.length > 0
|
|
90
|
+
? options.map((option: Option) =>
|
|
91
|
+
option.options
|
|
92
|
+
? [
|
|
58
93
|
h('div', { class: 'form-multi-select-optgroup-label' }, option.label),
|
|
59
94
|
createOptions(option.options),
|
|
60
|
-
]
|
|
95
|
+
]
|
|
61
96
|
: h(
|
|
62
97
|
'div',
|
|
63
98
|
{
|
|
@@ -65,17 +100,20 @@ const CMultiSelectOptions = defineComponent({
|
|
|
65
100
|
'form-multi-select-option',
|
|
66
101
|
{
|
|
67
102
|
'form-multi-select-option-with-checkbox': props.optionsStyle === 'checkbox',
|
|
68
|
-
'form-multi-selected':
|
|
103
|
+
'form-multi-selected': props.selected.some(
|
|
104
|
+
(_option) => _option.value === option.value,
|
|
105
|
+
),
|
|
69
106
|
disabled: option.disabled,
|
|
70
107
|
},
|
|
71
108
|
],
|
|
72
109
|
onClick: () => handleOptionClick(option),
|
|
110
|
+
onKeydown: (event: any) => handleKeyDown(event, option),
|
|
111
|
+
tabindex: 0,
|
|
73
112
|
},
|
|
74
113
|
option.text,
|
|
75
|
-
)
|
|
76
|
-
|
|
114
|
+
),
|
|
115
|
+
)
|
|
77
116
|
: h('div', { class: 'form-multi-select-options-empty' }, props.searchNoResultsLabel)
|
|
78
|
-
}
|
|
79
117
|
return () =>
|
|
80
118
|
h(
|
|
81
119
|
'div',
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import { App } from 'vue'
|
|
2
2
|
import { CPagination } from './CPagination'
|
|
3
3
|
import { CPaginationItem } from './CPaginationItem'
|
|
4
|
-
import { CSmartPagination } from './CSmartPagination'
|
|
5
4
|
|
|
6
5
|
const CPaginationPlugin = {
|
|
7
6
|
install: (app: App): void => {
|
|
8
7
|
app.component(CPagination.name, CPagination)
|
|
9
8
|
app.component(CPaginationItem.name, CPaginationItem)
|
|
10
|
-
app.component(CSmartPagination.name, CSmartPagination)
|
|
11
9
|
},
|
|
12
10
|
}
|
|
13
11
|
|
|
14
|
-
export { CPaginationPlugin, CPagination, CPaginationItem
|
|
12
|
+
export { CPaginationPlugin, CPagination, CPaginationItem }
|