@coreui/vue-pro 4.4.2 → 4.6.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.
Files changed (27) hide show
  1. package/dist/components/calendar/CCalendar.d.ts +41 -3
  2. package/dist/components/date-picker/CDatePicker.d.ts +41 -3
  3. package/dist/components/date-range-picker/CDateRangePicker.d.ts +160 -3
  4. package/dist/components/multi-select/CMultiSelect copy.d.ts +305 -0
  5. package/dist/components/multi-select/CMultiSelect.d.ts +168 -0
  6. package/dist/components/smart-table/CSmartTable.d.ts +2 -2
  7. package/dist/components/smart-table/CSmartTableHead.d.ts +15 -3
  8. package/dist/components/smart-table/CSmartTableInterface.d.ts +1 -1
  9. package/dist/components/table/CTable.d.ts +170 -8
  10. package/dist/components/table/CTableDataCell.d.ts +14 -0
  11. package/dist/index.es.js +1006 -474
  12. package/dist/index.es.js.map +1 -1
  13. package/dist/index.js +1006 -474
  14. package/dist/index.js.map +1 -1
  15. package/package.json +2 -2
  16. package/src/components/calendar/CCalendar.ts +46 -4
  17. package/src/components/date-picker/CDatePicker.ts +33 -1
  18. package/src/components/date-range-picker/CDateRangePicker.ts +286 -170
  19. package/src/components/form/CFormInput.ts +1 -1
  20. package/src/components/multi-select/CMultiSelect.ts +204 -93
  21. package/src/components/smart-table/CSmartTable.ts +22 -21
  22. package/src/components/smart-table/CSmartTableHead.ts +45 -24
  23. package/src/components/smart-table/CSmartTableInterface.ts +1 -1
  24. package/src/components/smart-table/CSmartTableItemsPerPageSelector.ts +1 -1
  25. package/src/components/table/CTable.ts +243 -9
  26. package/src/components/table/CTableDataCell.ts +9 -1
  27. package/src/components/time-picker/CTimePicker.ts +125 -44
@@ -1,4 +1,8 @@
1
- import { defineComponent, h, onMounted, onUnmounted, PropType, provide, ref, watch } from 'vue'
1
+ import { defineComponent, h, PropType, provide, ref, watch } from 'vue'
2
+
3
+ import { CFormControlWrapper } from './../form/CFormControlWrapper'
4
+ import { CPicker } from '../picker'
5
+
2
6
  import { CMultiSelectNativeSelect } from './CMultiSelectNativeSelect'
3
7
  import { CMultiSelectOptions } from './CMultiSelectOptions'
4
8
  import { CMultiSelectSelection } from './CMultiSelectSelection'
@@ -25,6 +29,58 @@ const CMultiSelect = defineComponent({
25
29
  required: false,
26
30
  default: true,
27
31
  },
32
+ /**
33
+ * Toggle the disabled state for the component.
34
+ */
35
+ disabled: {
36
+ type: Boolean,
37
+ required: false,
38
+ default: false,
39
+ },
40
+ /**
41
+ * Provide valuable, actionable feedback.
42
+ *
43
+ * @since 4.6.0
44
+ */
45
+ feedback: {
46
+ type: String,
47
+ },
48
+ /**
49
+ * Provide valuable, actionable feedback.
50
+ *
51
+ * @since 4.6.0
52
+ */
53
+ feedbackInvalid: {
54
+ type: String,
55
+ },
56
+ /**
57
+ * Provide valuable, actionable invalid feedback when using standard HTML form validation which applied two CSS pseudo-classes, `:invalid` and `:valid`.
58
+ *
59
+ * @since 4.6.0
60
+ */
61
+ feedbackValid: {
62
+ type: String,
63
+ },
64
+ /**
65
+ * The id global attribute defines an identifier (ID) that must be unique in the whole document.
66
+ */
67
+ id: {
68
+ type: String,
69
+ },
70
+ /**
71
+ * Set component validation state to invalid.
72
+ *
73
+ * @since 4.6.0
74
+ */
75
+ invalid: Boolean,
76
+ /**
77
+ * Add a caption for a component.
78
+ *
79
+ * @since 4.6.0
80
+ */
81
+ label: {
82
+ type: String,
83
+ },
28
84
  /**
29
85
  * It specifies that multiple options can be selected at once.
30
86
  *
@@ -137,6 +193,38 @@ const CMultiSelect = defineComponent({
137
193
  default: 'item(s) selected',
138
194
  required: false,
139
195
  },
196
+ /**
197
+ * Size the component small or large.
198
+ *
199
+ * @values 'sm', 'lg'
200
+ */
201
+ size: {
202
+ type: String,
203
+ required: false,
204
+ validator: (value: string) => {
205
+ return ['sm', 'lg'].includes(value)
206
+ },
207
+ },
208
+ /**
209
+ * Add helper text to the component.
210
+ *
211
+ * @since 4.6.0
212
+ */
213
+ text: {
214
+ type: String,
215
+ },
216
+ /**
217
+ * Display validation feedback in a styled tooltip.
218
+ *
219
+ * @since 4.6.0
220
+ */
221
+ tooltipFeedback: Boolean,
222
+ /**
223
+ * Set component validation state to valid.
224
+ *
225
+ * @since 4.6.0
226
+ */
227
+ valid: Boolean,
140
228
  /**
141
229
  * Toggle the visibility of multi select dropdown.
142
230
  *
@@ -154,7 +242,7 @@ const CMultiSelect = defineComponent({
154
242
  */
155
243
  'change',
156
244
  ],
157
- setup(props, { emit }) {
245
+ setup(props, { attrs, emit }) {
158
246
  const flattenArray = (options: Option[]): Option[] => {
159
247
  return options.reduce((acc: Option[], val: Option) => {
160
248
  return acc.concat(Array.isArray(val.options) ? flattenArray(val.options) : val)
@@ -239,7 +327,6 @@ const CMultiSelect = defineComponent({
239
327
  : options.value
240
328
  }
241
329
 
242
- const multiSelectRef = ref<HTMLDivElement>()
243
330
  const nativeSelectRef = ref<HTMLSelectElement>()
244
331
  provide('nativeSelectRef', nativeSelectRef)
245
332
  const searchRef = ref<HTMLInputElement>()
@@ -247,15 +334,15 @@ const CMultiSelect = defineComponent({
247
334
  const options = ref<Option[]>(props.options)
248
335
  const vOptions = ref<Option[]>(props.options)
249
336
  const search = ref('')
250
- const visible = ref(props.visible)
337
+ const visible = ref<Boolean>(props.visible)
251
338
 
252
339
  const selected = ref<Option[]>(getSelectedOptions(props.options))
253
340
  const count = ref<number>(0)
254
341
 
255
342
  watch(
256
343
  () => props.options,
257
- () => {
258
- options.value = props.options
344
+ (newValue, oldValue) => {
345
+ if (JSON.stringify(newValue) !== JSON.stringify(oldValue)) options.value = newValue
259
346
  },
260
347
  )
261
348
 
@@ -283,27 +370,6 @@ const CMultiSelect = defineComponent({
283
370
  nativeSelectRef.value.dispatchEvent(new Event('change', { bubbles: true }))
284
371
  })
285
372
 
286
- onMounted(() => {
287
- window.addEventListener('click', handleClickOutside)
288
- window.addEventListener('keyup', handleKeyup)
289
- })
290
-
291
- onUnmounted(() => {
292
- window.removeEventListener('click', handleClickOutside)
293
- window.removeEventListener('keyup', handleKeyup)
294
- })
295
-
296
- const handleKeyup = (event: Event) => {
297
- if (multiSelectRef.value && !multiSelectRef.value.contains(event.target as HTMLElement)) {
298
- visible.value = false
299
- }
300
- }
301
- const handleClickOutside = (event: Event) => {
302
- if (multiSelectRef.value && !multiSelectRef.value.contains(event.target as HTMLElement)) {
303
- visible.value = false
304
- }
305
- }
306
-
307
373
  const handleSearchChange = (event: InputEvent) => {
308
374
  const target = event.target as HTMLInputElement
309
375
  search.value = target.value.toLowerCase()
@@ -323,6 +389,14 @@ const CMultiSelect = defineComponent({
323
389
 
324
390
  const handleOptionClick = (option: Option) => {
325
391
  options.value = updateOptions(option.value)
392
+
393
+ if (!props.multiple) {
394
+ visible.value = false
395
+ search.value = ''
396
+ if (searchRef.value) {
397
+ searchRef.value.value = ''
398
+ }
399
+ }
326
400
  }
327
401
 
328
402
  const handleSelectAll = () => {
@@ -343,74 +417,111 @@ const CMultiSelect = defineComponent({
343
417
  onChange: () => emit('change', selected.value),
344
418
  }),
345
419
  h(
346
- 'div',
420
+ CFormControlWrapper,
421
+ {
422
+ describedby: attrs['aria-describedby'],
423
+ feedback: props.feedback,
424
+ feedbackInvalid: props.feedbackInvalid,
425
+ feedbackValid: props.feedbackValid,
426
+ id: props.id,
427
+ invalid: props.invalid,
428
+ label: props.label,
429
+ text: props.text,
430
+ tooltipFeedback: props.tooltipFeedback,
431
+ valid: props.valid,
432
+ },
347
433
  {
348
- class: [
349
- 'form-multi-select',
350
- {
351
- show: visible.value,
352
- 'form-multi-select-selection-tags': props.multiple && props.selectionType === 'tags',
353
- },
354
- ],
355
- onClick: () => {
356
- visible.value = true
357
- props.search && searchRef.value && searchRef.value.focus()
358
- },
359
- ref: multiSelectRef,
434
+ default: () =>
435
+ h(
436
+ CPicker,
437
+ {
438
+ class: [
439
+ 'form-multi-select',
440
+ {
441
+ 'form-multi-select-with-cleaner': props.cleaner,
442
+ disabled: props.disabled,
443
+ [`form-multi-select-${props.size}`]: props.size,
444
+ 'form-multi-select-selection-tags':
445
+ props.multiple && props.selectionType === 'tags',
446
+ show: visible.value,
447
+ 'is-invalid': props.invalid,
448
+ 'is-valid': props.valid,
449
+ },
450
+ ],
451
+ disabled: props.disabled,
452
+ id: props.id,
453
+ onHide: () => {
454
+ visible.value = false
455
+ },
456
+ onShow: () => {
457
+ props.search && searchRef.value && searchRef.value.focus()
458
+ visible.value = true
459
+ },
460
+ visible: visible.value,
461
+ },
462
+ {
463
+ toggler: () =>
464
+ h('div', {}, [
465
+ h(CMultiSelectSelection, {
466
+ multiple: props.multiple,
467
+ onRemove: (option: Option) => !props.disabled && handleOptionClick(option),
468
+ search: props.search,
469
+ selected: selected.value,
470
+ selectionType: props.selectionType,
471
+ selectionTypeCounterText: props.selectionTypeCounterText,
472
+ }),
473
+ props.multiple &&
474
+ props.cleaner &&
475
+ selected.value.length > 0 &&
476
+ !props.disabled &&
477
+ h('button', {
478
+ type: 'button',
479
+ class: 'form-multi-select-selection-cleaner',
480
+ onClick: () => handleDeselectAll(),
481
+ }),
482
+ props.search &&
483
+ h('input', {
484
+ type: 'text',
485
+ class: 'form-multi-select-search',
486
+ autocomplete: 'off',
487
+ ...(selected.value.length === 0 && { placeholder: props.placeholder }),
488
+ ...(selected.value.length &&
489
+ props.selectionType === 'counter' && {
490
+ placeholder: `${selected.value.length} ${props.selectionTypeCounterText}`,
491
+ }),
492
+ ...(selected.value.length &&
493
+ !props.multiple && {
494
+ placeholder: selected.value.map((option) => option.text)[0],
495
+ }),
496
+ disabled: props.disabled,
497
+ onInput: (event: InputEvent) => handleSearchChange(event),
498
+ onKeydown: (event: KeyboardEvent) => handleSearchKeyDown(event),
499
+ ...(props.multiple &&
500
+ selected.value.length &&
501
+ props.selectionType !== 'counter' && { size: search.value.length + 2 }),
502
+ ref: searchRef,
503
+ }),
504
+ ]),
505
+ default: () =>
506
+ h('div', {}, [
507
+ props.multiple &&
508
+ props.selectAll &&
509
+ h(
510
+ 'button',
511
+ { class: 'form-multi-select-all', onClick: () => handleSelectAll() },
512
+ props.selectAllLabel,
513
+ ),
514
+ h(CMultiSelectOptions, {
515
+ onOptionClick: (option: Option) => handleOptionClick(option),
516
+ options: vOptions.value,
517
+ optionsMaxHeight: props.optionsMaxHeight,
518
+ optionsStyle: props.optionsStyle,
519
+ searchNoResultsLabel: props.searchNoResultsLabel,
520
+ }),
521
+ ]),
522
+ },
523
+ ),
360
524
  },
361
- [
362
- h(CMultiSelectSelection, {
363
- multiple: props.multiple,
364
- onRemove: (option: Option) => handleOptionClick(option),
365
- search: props.search,
366
- selected: selected.value,
367
- selectionType: props.selectionType,
368
- selectionTypeCounterText: props.selectionTypeCounterText,
369
- }),
370
- props.multiple &&
371
- props.cleaner &&
372
- selected.value.length > 0 &&
373
- h('button', {
374
- type: 'button',
375
- class: 'form-multi-select-selection-cleaner',
376
- onClick: () => handleDeselectAll(),
377
- }),
378
- props.search &&
379
- h('input', {
380
- type: 'text',
381
- class: 'form-multi-select-search',
382
- autocomplete: 'off',
383
- ...(selected.value.length === 0 && { placeholder: props.placeholder }),
384
- ...(selected.value.length &&
385
- props.selectionType === 'counter' && {
386
- placeholder: `${selected.value.length} ${props.selectionTypeCounterText}`,
387
- }),
388
- ...(selected.value.length &&
389
- !props.multiple && { placeholder: selected.value.map((option) => option.text)[0] }),
390
- onInput: (event: InputEvent) => handleSearchChange(event),
391
- onKeydown: (event: KeyboardEvent) => handleSearchKeyDown(event),
392
- ...(props.multiple &&
393
- selected.value.length &&
394
- props.selectionType !== 'counter' && { size: search.value.length + 2 }),
395
- ref: searchRef,
396
- }),
397
- h('div', { class: 'form-multi-select-dropdown' }, [
398
- props.multiple &&
399
- props.selectAll &&
400
- h(
401
- 'button',
402
- { class: 'form-multi-select-all', onClick: () => handleSelectAll() },
403
- props.selectAllLabel,
404
- ),
405
- h(CMultiSelectOptions, {
406
- onOptionClick: (option: Option) => handleOptionClick(option),
407
- options: vOptions.value,
408
- optionsMaxHeight: props.optionsMaxHeight,
409
- optionsStyle: props.optionsStyle,
410
- searchNoResultsLabel: props.searchNoResultsLabel,
411
- }),
412
- ]),
413
- ],
414
525
  ),
415
526
  ]
416
527
  },
@@ -388,6 +388,9 @@ const CSmartTable = defineComponent({
388
388
 
389
389
  // functions
390
390
 
391
+ const isLazy = (columnFilter?: boolean | { lazy?: boolean; external?: boolean }) =>
392
+ columnFilter && typeof columnFilter === 'object' && columnFilter.lazy === true
393
+
391
394
  const isSortable = (i: number): boolean | undefined => {
392
395
  const isDataColumn = itemsDataColumns.value.includes(rawColumnNames.value[i])
393
396
  let column
@@ -470,12 +473,9 @@ const CSmartTable = defineComponent({
470
473
  })
471
474
  }
472
475
 
473
- const columnFilterChange = (colName: string, value: string, type: string): void => {
474
- const isLazy =
475
- props.columnFilter &&
476
- typeof props.columnFilter === 'object' &&
477
- props.columnFilter.lazy === true
478
- if ((isLazy && type === 'input') || (!isLazy && type === 'change')) {
476
+ const columnFilterChange = (colName: string, value: any, type?: string): void => {
477
+ const _isLazy = isLazy(props.columnFilter)
478
+ if ((_isLazy && type === 'input') || (!_isLazy && type === 'change')) {
479
479
  return
480
480
  }
481
481
  activePage.value = 1
@@ -484,11 +484,8 @@ const CSmartTable = defineComponent({
484
484
  }
485
485
 
486
486
  const tableFilterChange = (value: string, type: string): void => {
487
- const isLazy =
488
- props.columnFilter &&
489
- typeof props.columnFilter === 'object' &&
490
- props.columnFilter.lazy === true
491
- if ((isLazy && type === 'input') || (!isLazy && type === 'change')) {
487
+ const _isLazy = isLazy(props.columnFilter)
488
+ if ((_isLazy && type === 'input') || (!_isLazy && type === 'change')) {
492
489
  return
493
490
  }
494
491
  activePage.value = 1
@@ -524,7 +521,7 @@ const CSmartTable = defineComponent({
524
521
 
525
522
  // variables
526
523
 
527
- const columnFiltered = () => {
524
+ const filteredColumns = computed(() => {
528
525
  let _items = items.value
529
526
  if (
530
527
  props.columnFilter &&
@@ -534,6 +531,11 @@ const CSmartTable = defineComponent({
534
531
  return _items
535
532
  }
536
533
  Object.entries(columnFilterState.value).forEach(([key, value]) => {
534
+ if (value instanceof Function) {
535
+ _items = _items.filter((item) => value(item[key]))
536
+ return
537
+ }
538
+
537
539
  const columnFilter = String(value).toLowerCase()
538
540
  if (columnFilter && itemsDataColumns.value.includes(key)) {
539
541
  _items = _items.filter((item) => {
@@ -542,10 +544,10 @@ const CSmartTable = defineComponent({
542
544
  }
543
545
  })
544
546
  return _items
545
- }
547
+ })
546
548
 
547
- const tableFiltered = computed(() => {
548
- let items = columnFiltered()
549
+ const filteredTable = computed(() => {
550
+ let items = filteredColumns.value
549
551
  if (
550
552
  !tableFilterState.value ||
551
553
  (props.tableFilter && typeof props.tableFilter === 'object' && props.tableFilter.external)
@@ -570,12 +572,12 @@ const CSmartTable = defineComponent({
570
572
  typeof props.columnSorter === 'object' &&
571
573
  props.columnSorter.external)
572
574
  ) {
573
- return tableFiltered.value
575
+ return filteredTable.value
574
576
  }
575
577
  //if values in column are to be sorted by numeric value they all have to be type number
576
578
  // const flip = sorterState.asc ? 1 : -1
577
579
  const flip = sorterState.state === 'asc' ? 1 : sorterState.state === 'desc' ? -1 : 0
578
- const sorted = tableFiltered.value.slice().sort((item, item2) => {
580
+ const sorted = filteredTable.value.slice().sort((item, item2) => {
579
581
  const value = item[col]
580
582
  const value2 = item2[col]
581
583
  const a = typeof value === 'number' ? value : String(value).toLowerCase()
@@ -683,9 +685,12 @@ const CSmartTable = defineComponent({
683
685
  columnFilterValue: columnFilterState.value,
684
686
  columns: props.columns ? props.columns : rawColumnNames.value,
685
687
  columnSorter: props.columnSorter,
688
+ items: items.value,
686
689
  selectable: props.selectable,
687
690
  selectAll: selectedAll.value,
688
691
  sorterState: sorterState,
692
+ onCustomFilterChange: (key: string, value: any) =>
693
+ columnFilterChange(key, value),
689
694
  onFilterInput: (key: string, value: string) =>
690
695
  columnFilterChange(key, value, 'input'),
691
696
  onFilterChange: (key: string, value: string) =>
@@ -757,10 +762,6 @@ const CSmartTable = defineComponent({
757
762
  columns: props.columns ? props.columns : rawColumnNames.value,
758
763
  selectable: props.selectable,
759
764
  selectAll: selectedAll.value,
760
- onFilterInput: (key: string, value: string) =>
761
- columnFilterChange(key, value, 'input'),
762
- onFilterChange: (key: string, value: string) =>
763
- columnFilterChange(key, value, 'change'),
764
765
  onSelectAllChecked: () => handleSelectAllChecked(),
765
766
  }),
766
767
  ],
@@ -9,6 +9,7 @@ import {
9
9
  Column,
10
10
  ColumnFilter,
11
11
  ColumnFilterValue,
12
+ Item,
12
13
  Sorter,
13
14
  SorterValue,
14
15
  } from './CSmartTableInterface'
@@ -44,6 +45,11 @@ const CSmartTableHead = defineComponent({
44
45
  default: () => [],
45
46
  required: false,
46
47
  },
48
+ items: {
49
+ type: Array as PropType<Item[]>,
50
+ default: () => [],
51
+ required: false,
52
+ },
47
53
  selectable: Boolean,
48
54
  selectAll: [Boolean, String],
49
55
  sorterState: {
@@ -52,7 +58,7 @@ const CSmartTableHead = defineComponent({
52
58
  require: false,
53
59
  },
54
60
  },
55
- emits: ['filterInput', 'filterChange', 'selectAllChecked', 'sortClick'],
61
+ emits: ['customFilterChange', 'filterInput', 'filterChange', 'selectAllChecked', 'sortClick'],
56
62
  setup(props, { slots, emit }) {
57
63
  const handleSortClick = (key: string, index: number) => {
58
64
  emit('sortClick', key, index)
@@ -110,6 +116,10 @@ const CSmartTableHead = defineComponent({
110
116
  return 0
111
117
  }
112
118
 
119
+ const getValues = (items: Item[], key: string) => {
120
+ return items.map((a) => a[key])
121
+ }
122
+
113
123
  const columnSorterIcon = (column: Column | string) => {
114
124
  if (getColumnSorterState(key(column)) === 0) {
115
125
  return h(
@@ -135,6 +145,10 @@ const CSmartTableHead = defineComponent({
135
145
  return
136
146
  }
137
147
 
148
+ const handleOnCustomFilterChange = (key: string, value: any) => {
149
+ emit('customFilterChange', key, value)
150
+ }
151
+
138
152
  const handleFilterInput = (key: string, value: string) => {
139
153
  emit('filterInput', key, value)
140
154
  }
@@ -212,29 +226,36 @@ const CSmartTableHead = defineComponent({
212
226
  },
213
227
  {
214
228
  default: () =>
215
- (typeof column !== 'object'
216
- ? true
217
- : typeof column.filter === 'undefined'
218
- ? true
219
- : column.filter) &&
220
- h(CFormInput, {
221
- size: 'sm',
222
- onInput: (event: Event) =>
223
- handleFilterInput(
224
- key(column),
225
- (event.target as HTMLInputElement).value,
226
- ),
227
- onChange: (event: Event) =>
228
- handleFilterChange(
229
- key(column),
230
- (event.target as HTMLInputElement).value,
231
- ),
232
- 'aria-label': `column name: '${label(column)}' filter input`,
233
- ...(props.columnFilterValue &&
234
- props.columnFilterValue[key(column)] && {
235
- value: props.columnFilterValue[key(column)],
236
- }),
237
- }),
229
+ (
230
+ typeof column !== 'object'
231
+ ? true
232
+ : typeof column.filter === 'undefined'
233
+ ? true
234
+ : column.filter
235
+ )
236
+ ? typeof column !== 'string' && typeof column.filter === 'function'
237
+ ? column.filter(getValues(props.items, key(column)), (value: any) =>
238
+ handleOnCustomFilterChange(key(column), value),
239
+ )
240
+ : h(CFormInput, {
241
+ size: 'sm',
242
+ onInput: (event: Event) =>
243
+ handleFilterInput(
244
+ key(column),
245
+ (event.target as HTMLInputElement).value,
246
+ ),
247
+ onChange: (event: Event) =>
248
+ handleFilterChange(
249
+ key(column),
250
+ (event.target as HTMLInputElement).value,
251
+ ),
252
+ 'aria-label': `column name: '${label(column)}' filter input`,
253
+ ...(props.columnFilterValue &&
254
+ props.columnFilterValue[key(column)] && {
255
+ value: props.columnFilterValue[key(column)],
256
+ }),
257
+ })
258
+ : '',
238
259
  },
239
260
  ),
240
261
  ),
@@ -4,7 +4,7 @@
4
4
  /* eslint-disable no-unused-vars */
5
5
  /* eslint-disable @typescript-eslint/ban-types */
6
6
  export interface Column {
7
- filter?: boolean
7
+ filter?: boolean | ((values: any[], onChange: (value: any) => void) => VNode)
8
8
  key: string
9
9
  label?: string
10
10
  sorter?: boolean
@@ -54,7 +54,7 @@ const CSmartTableItemsPerPageSelector = defineComponent({
54
54
  h(
55
55
  CFormSelect,
56
56
  {
57
- defaultValue: props.itemsPerPage,
57
+ value: props.itemsPerPage,
58
58
  onChange: handleChange,
59
59
  },
60
60
  {