@coreui/vue-pro 4.7.0 → 4.8.0-next.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 (34) hide show
  1. package/dist/components/calendar/utils.d.ts +23 -0
  2. package/dist/components/modal/CModal.d.ts +4 -20
  3. package/dist/components/offcanvas/COffcanvas.d.ts +35 -18
  4. package/dist/components/smart-table/CSmartTable.d.ts +65 -87
  5. package/dist/components/smart-table/CSmartTableBody.d.ts +16 -40
  6. package/dist/components/smart-table/CSmartTableHead.d.ts +17 -58
  7. package/dist/components/smart-table/CSmartTableInterface.d.ts +1 -1
  8. package/dist/components/smart-table/types.d.ts +50 -0
  9. package/dist/components/smart-table/utils.d.ts +17 -0
  10. package/dist/components/table/CTable.d.ts +1 -1
  11. package/dist/components/time-picker/types.d.ts +15 -0
  12. package/dist/components/time-picker/utils.d.ts +23 -0
  13. package/dist/index.es.js +752 -793
  14. package/dist/index.es.js.map +1 -1
  15. package/dist/index.js +752 -793
  16. package/dist/index.js.map +1 -1
  17. package/dist/utils/isObjectInArray.d.ts +2 -0
  18. package/package.json +6 -6
  19. package/src/components/calendar/CCalendar.ts +1 -1
  20. package/src/{utils/calendar.ts → components/calendar/utils.ts} +1 -1
  21. package/src/components/date-range-picker/CDateRangePicker.ts +1 -1
  22. package/src/components/element-cover/CElementCover.ts +14 -14
  23. package/src/components/modal/CModal.ts +10 -10
  24. package/src/components/multi-select/CMultiSelect.ts +0 -10
  25. package/src/components/offcanvas/COffcanvas.ts +50 -28
  26. package/src/components/smart-table/CSmartTable.ts +365 -268
  27. package/src/components/smart-table/CSmartTableBody.ts +126 -137
  28. package/src/components/smart-table/CSmartTableHead.ts +53 -138
  29. package/src/components/smart-table/CSmartTableInterface.ts +1 -1
  30. package/src/components/smart-table/types.ts +61 -0
  31. package/src/components/smart-table/utils.ts +212 -0
  32. package/src/components/time-picker/CTimePicker.ts +49 -27
  33. package/src/components/time-picker/types.ts +15 -0
  34. package/src/{utils/time.ts → components/time-picker/utils.ts} +43 -2
@@ -1,21 +1,27 @@
1
- import { computed, defineComponent, h, reactive, ref, PropType, watch, onMounted } from 'vue'
1
+ import { computed, defineComponent, h, ref, PropType, watch, onMounted } from 'vue'
2
2
 
3
- import { CElementCover } from '../element-cover/CElementCover'
4
- import { CSmartPagination } from '../smart-pagination/CSmartPagination'
3
+ import { cilArrowTop, cilArrowBottom, cilFilterX, cilSwapVertical } from '@coreui/icons'
4
+ import { CIcon } from '@coreui/icons-vue'
5
5
 
6
- import { CTable, CTableDataCell, CTableFoot, CTableRow } from '../table/'
6
+ import { CElementCover } from '../element-cover'
7
+ import { CFormInput, CFormLabel, CFormSelect } from '../form'
8
+ import { CSmartPagination } from '../smart-pagination'
9
+ import { CTable, CTableDataCell, CTableFoot, CTableRow } from '../table'
7
10
 
8
11
  import { CSmartTableBody } from './CSmartTableBody'
9
12
  import { CSmartTableHead } from './CSmartTableHead'
10
- import { CSmartTableFilter } from './CSmartTableFilter'
11
- import { CSmartTableCleaner } from './CSmartTableCleaner'
12
- import { CSmartTableItemsPerPageSelector } from './CSmartTableItemsPerPageSelector'
13
-
14
- import { CIcon } from '@coreui/icons-vue'
15
-
16
- import { cilArrowTop, cilArrowBottom, cilFilterX, cilSwapVertical } from '@coreui/icons'
17
13
 
18
14
  import {
15
+ filterColumns,
16
+ filterTable,
17
+ getColumnNames,
18
+ getColumnNamesFromItems,
19
+ isObjectInArray,
20
+ isSortable,
21
+ sortItems,
22
+ } from './utils'
23
+
24
+ import type {
19
25
  Column,
20
26
  ColumnFilter,
21
27
  ColumnFilterValue,
@@ -26,7 +32,7 @@ import {
26
32
  Sorter,
27
33
  SorterValue,
28
34
  TableFilter,
29
- } from './CSmartTableInterface'
35
+ } from './types'
30
36
 
31
37
  const CSmartTable = defineComponent({
32
38
  name: 'CSmartTable',
@@ -37,7 +43,6 @@ const CSmartTable = defineComponent({
37
43
  activePage: {
38
44
  type: Number,
39
45
  default: 1,
40
- required: false,
41
46
  },
42
47
  /**
43
48
  * When set, displays table cleaner above table, next to the table filter (or in place of table filter if `tableFilter` prop is not set)
@@ -46,14 +51,12 @@ const CSmartTable = defineComponent({
46
51
  */
47
52
  cleaner: {
48
53
  type: Boolean,
49
- required: false,
50
54
  },
51
55
  /**
52
56
  * Style table items as clickable.
53
57
  */
54
58
  clickableRows: {
55
59
  type: Boolean,
56
- required: false,
57
60
  },
58
61
  /**
59
62
  * When set, displays additional filter row between table header and items, allowing filtering by specific column.
@@ -63,7 +66,6 @@ const CSmartTable = defineComponent({
63
66
  */
64
67
  columnFilter: {
65
68
  type: [Boolean, Object] as PropType<boolean | ColumnFilter>,
66
- required: false,
67
69
  },
68
70
  /**
69
71
  * Value of table filter. To set pass object where keys are column names and values are filter strings e.g.:
@@ -71,8 +73,6 @@ const CSmartTable = defineComponent({
71
73
  */
72
74
  columnFilterValue: {
73
75
  type: Object as PropType<ColumnFilterValue>,
74
- default: undefined,
75
- required: false,
76
76
  },
77
77
  /**
78
78
  * Prop for table columns configuration. If prop is not defined, table will display columns based on the first item keys, omitting keys that begins with underscore (e.g. '_props')
@@ -89,7 +89,6 @@ const CSmartTable = defineComponent({
89
89
  */
90
90
  columns: {
91
91
  type: Array as PropType<(Column | string)[]>,
92
- required: false,
93
92
  },
94
93
  /**
95
94
  * Enables table sorting by column value. Sorting will be performed corectly only if values in column are of one type: string (case insensitive) or number.
@@ -100,8 +99,6 @@ const CSmartTable = defineComponent({
100
99
  */
101
100
  columnSorter: {
102
101
  type: [Boolean, Object] as PropType<boolean | Sorter>,
103
- default: undefined,
104
- required: false,
105
102
  },
106
103
  /**
107
104
  * If `true` Displays table footer, which mirrors table header. (without column filter).
@@ -114,14 +111,12 @@ const CSmartTable = defineComponent({
114
111
  */
115
112
  footer: {
116
113
  type: [Boolean, Array] as PropType<boolean | (FooterItem | string)[]>,
117
- required: false,
118
114
  },
119
115
  /**
120
116
  * Set to false to remove table header.
121
117
  */
122
118
  header: {
123
119
  type: Boolean,
124
- required: false,
125
120
  default: true,
126
121
  },
127
122
  /**
@@ -134,22 +129,25 @@ const CSmartTable = defineComponent({
134
129
  items: {
135
130
  type: Array as PropType<Item[]>,
136
131
  default: () => [],
137
- required: false,
138
132
  },
133
+ /**
134
+ * The total number of items. Use if you pass a portion of data from an external source to let know component what is the total number of items.
135
+ *
136
+ * @since 4.8.0
137
+ */
138
+ itemsNumber: Number,
139
139
  /**
140
140
  * Number of items per site, when pagination is enabled.
141
141
  */
142
142
  itemsPerPage: {
143
143
  type: Number,
144
144
  default: 10,
145
- required: false,
146
145
  },
147
146
  /**
148
147
  * Label for items per page selector.
149
148
  */
150
149
  itemsPerPageLabel: {
151
150
  type: String,
152
- required: false,
153
151
  default: 'Items per page:',
154
152
  },
155
153
  /**
@@ -158,7 +156,6 @@ const CSmartTable = defineComponent({
158
156
  itemsPerPageOptions: {
159
157
  type: Array as PropType<number[]>,
160
158
  default: () => [5, 10, 20, 50],
161
- required: false,
162
159
  },
163
160
  /**
164
161
  * Adds select element over table, which is used for control items per page in pagination. If you want to customize this element, pass object with optional values:
@@ -168,15 +165,12 @@ const CSmartTable = defineComponent({
168
165
  */
169
166
  itemsPerPageSelect: {
170
167
  type: [Boolean, Object] as PropType<boolean | ItemsPerPageSelect>,
171
- default: undefined,
172
- required: false,
173
168
  },
174
169
  /**
175
170
  * When set, table will have loading style: loading spinner and reduced opacity. When 'small' prop is enabled spinner will be also smaller.
176
171
  */
177
172
  loading: {
178
173
  type: Boolean,
179
- required: false,
180
174
  },
181
175
  /**
182
176
  * ReactNode or string for passing custom noItemsLabel texts.
@@ -184,51 +178,63 @@ const CSmartTable = defineComponent({
184
178
  noItemsLabel: {
185
179
  type: String,
186
180
  default: 'No items found',
187
- required: false,
188
181
  },
189
182
  /**
190
183
  * Enables default pagination. Set to true for default setup or pass an object with additional CPagination props. Default pagination will always have the computed number of pages that cannot be changed. The number of pages is generated based on the number of passed items and 'itemsPerPage' prop. If this restriction is an obstacle, you can make external CPagination instead.
191
184
  */
192
185
  pagination: {
193
186
  type: [Boolean, Object] as PropType<boolean | Pagination>,
194
- required: false,
195
187
  },
196
188
  /**
197
189
  * Properties to [CSmartPagination](https://coreui.io/vue/docs/components/smart-pagination#csmartpagination) component.
198
190
  */
199
191
  paginationProps: {
200
192
  type: Object,
201
- default: undefined,
202
- required: false,
203
193
  },
204
194
  /**
205
195
  * Add checkboxes to make table rows selectable.
206
196
  */
207
197
  selectable: Boolean,
198
+ /**
199
+ * Enables select all checkbox displayed in the header of the table.
200
+ *
201
+ * Can be customized, by passing prop as object with additional options as keys. Available options:
202
+ * - external (Boolean) - Disables automatic selection inside the component.
203
+ *
204
+ * @since 4.8.0
205
+ */
206
+ selectAll: {
207
+ type: [Boolean, Object] as PropType<boolean | { external?: boolean }>,
208
+ },
209
+ /**
210
+ * Array of selected objects, where each object represents one item - row in table.
211
+ *
212
+ * Example item: `{ name: 'John' , age: 12 }`
213
+ *
214
+ * @since 4.8.0
215
+ */
216
+ selected: {
217
+ type: Array as PropType<Item[]>,
218
+ default: () => [],
219
+ },
208
220
  /**
209
221
  * State of the sorter. Name key is column name, direction can be 'asc' or 'desc'. eg.:
210
222
  * { column: 'status', state: 'asc' }
211
223
  */
212
224
  sorterValue: {
213
225
  type: Object as PropType<SorterValue>,
214
- default: undefined,
215
- required: false,
216
226
  },
217
227
  /**
218
228
  * Properties to [CTableBody](https://coreui.io/vue/docs/components/table/#ctablebody) component.
219
229
  */
220
230
  tableBodyProps: {
221
231
  type: Object,
222
- default: undefined,
223
- required: false,
224
232
  },
225
233
  /**
226
234
  * Properties to [CTableFoot](https://coreui.io/vue/docs/components/table/#ctablefoot) component.
227
235
  */
228
236
  tableFootProps: {
229
237
  type: Object,
230
- default: undefined,
231
- required: false,
232
238
  },
233
239
  /**
234
240
  * When set, displays table filter above table, allowing filtering by specific column.
@@ -239,7 +245,6 @@ const CSmartTable = defineComponent({
239
245
  */
240
246
  tableFilter: {
241
247
  type: [Boolean, Object] as PropType<boolean | TableFilter>,
242
- required: false,
243
248
  },
244
249
  /**
245
250
  * The element represents a caption for a component.
@@ -247,7 +252,6 @@ const CSmartTable = defineComponent({
247
252
  tableFilterLabel: {
248
253
  type: String,
249
254
  default: 'Filter:',
250
- required: false,
251
255
  },
252
256
  /**
253
257
  * Specifies a short hint that is visible in the search input.
@@ -255,31 +259,24 @@ const CSmartTable = defineComponent({
255
259
  tableFilterPlaceholder: {
256
260
  type: String,
257
261
  default: 'type string...',
258
- required: false,
259
262
  },
260
263
  /**
261
264
  * Value of table filter.
262
265
  */
263
266
  tableFilterValue: {
264
267
  type: String,
265
- default: undefined,
266
- required: false,
267
268
  },
268
269
  /**
269
270
  * Properties to [CTableHead](https://coreui.io/vue/docs/components/table/#ctablehead) component.
270
271
  */
271
272
  tableHeadProps: {
272
273
  type: Object,
273
- default: undefined,
274
- required: false,
275
274
  },
276
275
  /**
277
276
  * Properties to [CTable](https://coreui.io/vue/docs/components/table/#ctable) component.
278
277
  */
279
278
  tableProps: {
280
279
  type: Object,
281
- default: undefined,
282
- required: false,
283
280
  },
284
281
  },
285
282
  emits: [
@@ -316,6 +313,12 @@ const CSmartTable = defineComponent({
316
313
  * @property {event} event
317
314
  */
318
315
  'rowClick',
316
+ /**
317
+ * Select all callback.
318
+ *
319
+ * @since 4.8.0
320
+ */
321
+ 'selectAll',
319
322
  /**
320
323
  * Selected items change callback.
321
324
  *
@@ -336,56 +339,122 @@ const CSmartTable = defineComponent({
336
339
  'tableFilterChange',
337
340
  ],
338
341
  setup(props, { emit, slots }) {
339
- // reactive data
342
+ const activePage = ref(props.activePage)
343
+ const columnFilterState = ref<ColumnFilterValue>(
344
+ props.columnFilterValue ? props.columnFilterValue : {},
345
+ )
340
346
  const items = ref<Item[]>(
341
347
  props.items.map((item: Item, index: number) => {
342
348
  return { ...item, _id: index }
343
349
  }),
344
350
  )
351
+ const itemsNumber = ref(props.itemsNumber)
352
+ const itemsPerPage = ref<number>(props.itemsPerPage || items.value.length)
353
+ const selected = ref<Item[]>([])
354
+ const selectedAll = ref<boolean | string>()
355
+ const sorterState = ref<SorterValue>(props.sorterValue || {})
356
+ const tableFilterState = ref(props.tableFilterValue ? props.tableFilterValue : '')
357
+
358
+ watch(
359
+ () => props.activePage,
360
+ () => {
361
+ activePage.value = props.activePage
362
+ },
363
+ )
364
+
365
+ watch(
366
+ () => props.columnFilterValue,
367
+ () => {
368
+ if (props.columnFilterValue) {
369
+ columnFilterState.value = props.columnFilterValue
370
+ }
371
+ },
372
+ )
345
373
 
346
374
  watch(
347
375
  () => props.items,
348
376
  () => {
349
- items.value = props.items.map((item: Item, index: number) => {
350
- return { ...item, _id: index }
351
- })
352
377
  if (
353
- items.value &&
354
- items.value.length < itemsPerPage.value * activePage.value - itemsPerPage.value
378
+ props.items &&
379
+ props.items.length < itemsPerPage.value * activePage.value - itemsPerPage.value
355
380
  ) {
356
381
  activePage.value = 1
357
382
  }
383
+
384
+ props.items.forEach((item: Item) => {
385
+ if (item._selected) {
386
+ const _item = { ...item }
387
+ delete _item['_cellProps']
388
+ delete _item['_props']
389
+ delete _item['_selected']
390
+
391
+ selected.value = [...selected.value, _item]
392
+ }
393
+ })
394
+
395
+ if (Array.isArray(props.items)) {
396
+ items.value = props.items
397
+ itemsNumber.value = props.itemsNumber || props.items.length
398
+ }
399
+ },
400
+ )
401
+
402
+ watch(
403
+ () => props.itemsNumber,
404
+ () => {
405
+ itemsNumber.value = props.itemsNumber
406
+ },
407
+ )
408
+
409
+ watch(
410
+ () => props.itemsPerPage,
411
+ () => {
412
+ itemsPerPage.value = props.itemsPerPage
413
+ },
414
+ )
415
+
416
+ watch(
417
+ () => props.selected,
418
+ () => {
419
+ selected.value = props.selected
420
+ },
421
+ )
422
+
423
+ watch(
424
+ () => props.sorterValue,
425
+ () => {
426
+ if (props.sorterValue) {
427
+ sorterState.value = props.sorterValue
428
+ }
358
429
  },
359
430
  )
360
431
 
361
- const selectedAll = ref()
432
+ watch(itemsPerPage, () => {
433
+ if (props.itemsPerPage !== itemsPerPage.value) {
434
+ activePage.value = 1 // TODO: set proper page after _itemsPerPage update
435
+ }
362
436
 
363
- watch(items, () => {
364
- const selected = items.value.filter((item) => item._selected === true)
437
+ emit('itemsPerPageChange', itemsPerPage.value)
438
+ })
439
+
440
+ watch([selected, itemsNumber], () => {
365
441
  emit('selectedItemsChange', selected)
366
442
 
367
- if (selected.length === items.value.length) {
443
+ if (selected.value.length === itemsNumber.value) {
368
444
  selectedAll.value = true
369
445
  return
370
446
  }
371
447
 
372
- if (selected.length === 0) {
448
+ if (selected.value.length === 0) {
373
449
  selectedAll.value = false
374
450
  return
375
451
  }
376
452
 
377
- if (selected.length !== 0 && selected.length !== items.value.length) {
453
+ if (selected.value.length !== 0 && selected.value.length !== itemsNumber.value) {
378
454
  selectedAll.value = 'indeterminate'
379
455
  }
380
456
  })
381
457
 
382
- const itemsPerPage = ref<number>(props.itemsPerPage || items.value.length)
383
- const activePage = ref(props.activePage)
384
-
385
- const sorterState: SorterValue = reactive(props.sorterValue || {})
386
- const columnFilterState = ref(props.columnFilterValue ? props.columnFilterValue : {})
387
- const tableFilterState = ref(props.tableFilterValue ? props.tableFilterValue : '')
388
-
389
458
  onMounted(() => {
390
459
  if (
391
460
  items.value &&
@@ -395,31 +464,21 @@ const CSmartTable = defineComponent({
395
464
  }
396
465
  })
397
466
 
398
- // functions
399
-
400
- const isLazy = (columnFilter?: boolean | { lazy?: boolean; external?: boolean }) =>
401
- columnFilter && typeof columnFilter === 'object' && columnFilter.lazy === true
402
-
403
- const isSortable = (i: number): boolean | undefined => {
404
- const isDataColumn = itemsDataColumns.value.includes(rawColumnNames.value[i])
405
- let column
406
- if (props.columns) column = props.columns[i]
407
- return (
408
- props.columnSorter &&
409
- (!props.columns ||
410
- typeof column !== 'object' ||
411
- (typeof column === 'object' &&
412
- (typeof column.sorter === 'undefined' || column.sorter))) &&
413
- isDataColumn
414
- )
415
- }
416
-
417
- const sorterChange = (column: string, index: number): void => {
418
- if (!isSortable(index)) {
467
+ const handleSorterChange = (column: string, index: number) => {
468
+ if (
469
+ !isSortable(
470
+ index,
471
+ props.columns,
472
+ props.columnSorter,
473
+ itemsDataColumns.value,
474
+ columnNames.value,
475
+ )
476
+ ) {
419
477
  return
420
478
  }
479
+
421
480
  //if column changed or sort was descending change asc to true
422
- const state = sorterState
481
+ const state = sorterState.value
423
482
 
424
483
  if (state.column === column) {
425
484
  if (state.state === 0) {
@@ -437,10 +496,11 @@ const CSmartTable = defineComponent({
437
496
  state.column = column
438
497
  state.state = 'asc'
439
498
  }
440
- sorterState.column = state.column
441
- sorterState.state = state.state
442
499
 
443
- emit('sorterChange', sorterState)
500
+ sorterState.value.column = state.column
501
+ sorterState.value.state = state.state
502
+
503
+ emit('sorterChange', sorterState.value)
444
504
  }
445
505
 
446
506
  const handleActivePageChange = (page: number) => {
@@ -448,153 +508,110 @@ const CSmartTable = defineComponent({
448
508
  emit('activePageChange', page)
449
509
  }
450
510
 
451
- const handleItemsPerPageChange = (itemsPerPageNumber: number) => {
452
- itemsPerPage.value = itemsPerPageNumber
453
- itemsPerPageNumber !== props.itemsPerPage && handleActivePageChange(1) // TODO: set proper page after _itemsPerPage update
454
- emit('itemsPerPageChange', itemsPerPageNumber)
511
+ const handleItemsPerPageChange = (event: Event) => {
512
+ if (
513
+ typeof props.itemsPerPageSelect !== 'object' ||
514
+ (typeof props.itemsPerPageSelect === 'object' && !props.itemsPerPageSelect.external)
515
+ ) {
516
+ itemsPerPage.value = Number((event.target as HTMLSelectElement).value)
517
+ }
455
518
  }
456
519
 
457
- const handleRowChecked = (id: number, value: boolean) => {
458
- const newArr = [...items.value]
459
- newArr[id]._selected = value
460
- items.value = newArr
461
- }
520
+ const handleRowChecked = (item: Item, value: boolean) => {
521
+ if (value && !isObjectInArray(selected.value, item, ['_cellProps', '_props', '_selected'])) {
522
+ selected.value = [...selected.value, item]
523
+ return
524
+ }
462
525
 
463
- const handleRowClick = (
464
- item: Item,
465
- index: number,
466
- columnName: string,
467
- event: MouseEvent | boolean,
468
- ) => {
469
- emit('rowClick', item, index, columnName, event)
526
+ selected.value = selected.value.filter(
527
+ (_item: Item) => !isObjectInArray([_item], item, ['_cellProps', '_props', '_selected']),
528
+ )
470
529
  }
471
530
 
472
531
  const handleSelectAllChecked = () => {
473
532
  if (selectedAll.value === true) {
474
- items.value = items.value.map((item: Item) => {
475
- return { ...item, _selected: false }
476
- })
533
+ selected.value = []
477
534
  return
478
535
  }
479
536
 
480
- items.value = items.value.map((item: Item) => {
481
- return { ...item, _selected: true }
537
+ emit('selectAll')
538
+
539
+ if (props.selectAll && typeof props.selectAll === 'object' && props.selectAll.external) {
540
+ return
541
+ }
542
+
543
+ selected.value = items.value.map((item) => {
544
+ delete item['_cellProps']
545
+ delete item['_props']
546
+ delete item['_selected']
547
+
548
+ return item
482
549
  })
483
550
  }
484
551
 
485
- const columnFilterChange = (colName: string, value: any, type?: string): void => {
486
- const _isLazy = isLazy(props.columnFilter)
552
+ const handleColumnFilterChange = (colName: string, value: any, type?: string) => {
553
+ const _isLazy =
554
+ props.columnFilter &&
555
+ typeof props.columnFilter === 'object' &&
556
+ props.columnFilter.lazy === true
487
557
  if ((_isLazy && type === 'input') || (!_isLazy && type === 'change')) {
488
558
  return
489
559
  }
560
+
490
561
  activePage.value = 1
491
562
  columnFilterState.value = { ...columnFilterState.value, [`${colName}`]: value }
563
+
492
564
  emit('columnFilterChange', columnFilterState.value)
493
565
  }
494
566
 
495
- const tableFilterChange = (value: string, type: string): void => {
496
- const _isLazy = isLazy(props.columnFilter)
567
+ const handleTableFilterChange = (value: string, type: string) => {
568
+ const _isLazy =
569
+ props.columnFilter &&
570
+ typeof props.columnFilter === 'object' &&
571
+ props.columnFilter.lazy === true
497
572
  if ((_isLazy && type === 'input') || (!_isLazy && type === 'change')) {
498
573
  return
499
574
  }
575
+
500
576
  activePage.value = 1
501
577
  tableFilterState.value = value
502
- emit('tableFilterChange', tableFilterState)
578
+
579
+ emit('tableFilterChange', tableFilterState.value)
503
580
  }
504
581
 
505
- const clean = (): void => {
582
+ const handleClean = () => {
506
583
  tableFilterState.value = ''
507
584
  columnFilterState.value = {}
508
- sorterState.column = ''
509
- sorterState.state = ''
585
+ sorterState.value = {}
510
586
  }
511
587
 
512
- // computed
513
-
514
- const genCols = computed(() =>
515
- Object.keys(items.value[0] || {}).filter((el) => el.charAt(0) !== '_'),
516
- )
517
-
518
- const rawColumnNames = computed(() =>
519
- props.columns
520
- ? props.columns.map((column: Column | string) => {
521
- if (typeof column === 'object') return column.key
522
- else return column
523
- })
524
- : genCols.value,
525
- ) //! || el
588
+ const columnNames = computed(() => getColumnNames(props.columns, items.value))
526
589
 
527
590
  const itemsDataColumns = computed(() =>
528
- rawColumnNames.value.filter((name) => genCols.value.includes(name)),
591
+ columnNames.value.filter((name) => getColumnNamesFromItems(items.value).includes(name)),
529
592
  )
530
593
 
531
- // variables
532
-
533
- const filteredColumns = computed(() => {
534
- let _items = items.value
535
- if (
536
- props.columnFilter &&
537
- typeof props.columnFilter === 'object' &&
538
- props.columnFilter.external
539
- ) {
540
- return _items
541
- }
542
- Object.entries(columnFilterState.value).forEach(([key, value]) => {
543
- if (value instanceof Function) {
544
- _items = _items.filter((item) => value(item[key]))
545
- return
546
- }
547
-
548
- const columnFilter = String(value).toLowerCase()
549
- if (columnFilter && itemsDataColumns.value.includes(key)) {
550
- _items = _items.filter((item) => {
551
- return String(item[key]).toLowerCase().includes(columnFilter)
552
- })
553
- }
554
- })
555
- return _items
556
- })
594
+ const filteredColumns = computed(() =>
595
+ filterColumns(
596
+ items.value,
597
+ props.columnFilter,
598
+ columnFilterState.value,
599
+ itemsDataColumns.value,
600
+ ),
601
+ )
557
602
 
558
- const filteredTable = computed(() => {
559
- let items = filteredColumns.value
560
- if (
561
- !tableFilterState.value ||
562
- (props.tableFilter && typeof props.tableFilter === 'object' && props.tableFilter.external)
563
- ) {
564
- return items
565
- }
566
- const filter = tableFilterState.value.toLowerCase()
567
- const valueContainFilter = (val: any) => String(val).toLowerCase().includes(filter)
568
- items = items.filter((item) => {
569
- return !!itemsDataColumns.value.find((key) => valueContainFilter(item[key]))
570
- })
571
- emit('filteredItemsChange', items)
572
- return items
573
- })
603
+ const filteredTable = computed(() =>
604
+ filterTable(
605
+ filteredColumns.value,
606
+ props.tableFilter,
607
+ tableFilterState.value,
608
+ itemsDataColumns.value,
609
+ ),
610
+ )
574
611
 
575
- const sortedItems = computed(() => {
576
- const col = sorterState.column
577
- if (
578
- !col ||
579
- !itemsDataColumns.value.includes(col) ||
580
- (props.columnSorter &&
581
- typeof props.columnSorter === 'object' &&
582
- props.columnSorter.external)
583
- ) {
584
- return filteredTable.value
585
- }
586
- //if values in column are to be sorted by numeric value they all have to be type number
587
- // const flip = sorterState.asc ? 1 : -1
588
- const flip = sorterState.state === 'asc' ? 1 : sorterState.state === 'desc' ? -1 : 0
589
- const sorted = filteredTable.value.slice().sort((item, item2) => {
590
- const value = item[col]
591
- const value2 = item2[col]
592
- const a = typeof value === 'number' ? value : String(value).toLowerCase()
593
- const b = typeof value2 === 'number' ? value2 : String(value2).toLowerCase()
594
- return a > b ? 1 * flip : b > a ? -1 * flip : 0
595
- })
596
- return sorted
597
- })
612
+ const sortedItems = computed(() =>
613
+ sortItems(props.columnSorter, filteredTable.value, itemsDataColumns.value, sorterState.value),
614
+ )
598
615
 
599
616
  const numberOfPages = computed(() =>
600
617
  itemsPerPage.value ? Math.ceil(sortedItems.value.length / itemsPerPage.value) : 1,
@@ -604,25 +621,15 @@ const CSmartTable = defineComponent({
604
621
  activePage.value ? (activePage.value - 1) * itemsPerPage.value : 0,
605
622
  )
606
623
 
607
- const itemsOnActivePage = computed(() =>
608
- sortedItems.value.slice(
609
- firstItemOnActivePageIndex.value,
610
- firstItemOnActivePageIndex.value + itemsPerPage.value,
611
- ),
612
- )
613
-
614
624
  const currentItems = computed(() =>
615
- activePage.value ? itemsOnActivePage.value : sortedItems.value,
625
+ activePage.value
626
+ ? sortedItems.value.slice(
627
+ firstItemOnActivePageIndex.value,
628
+ firstItemOnActivePageIndex.value + itemsPerPage.value,
629
+ )
630
+ : sortedItems.value,
616
631
  )
617
632
 
618
- const isFiltered = computed(() => {
619
- return (
620
- tableFilterState.value ||
621
- sorterState.column ||
622
- Object.values(columnFilterState.value).join('')
623
- )
624
- })
625
-
626
633
  return () =>
627
634
  h('div', {}, [
628
635
  (props.tableFilter || props.cleaner) &&
@@ -639,13 +646,47 @@ const CSmartTable = defineComponent({
639
646
  class: 'col-auto p-0',
640
647
  },
641
648
  props.tableFilter &&
642
- h(CSmartTableFilter, {
643
- filterLabel: props.tableFilterLabel,
644
- filterPlaceholder: props.tableFilterPlaceholder,
645
- onFilterInput: (value: string) => tableFilterChange(value, 'input'),
646
- onFilterChange: (value: string) => tableFilterChange(value, 'change'),
647
- value: tableFilterState.value,
648
- }),
649
+ h(
650
+ 'div',
651
+ {
652
+ class: 'row mb-2',
653
+ },
654
+ {
655
+ default: () => [
656
+ h(
657
+ CFormLabel,
658
+ {
659
+ class: 'col-sm-auto col-form-label',
660
+ },
661
+ {
662
+ default: () => props.tableFilterLabel,
663
+ },
664
+ ),
665
+ h(
666
+ 'div',
667
+ {
668
+ class: 'col-sm-auto',
669
+ },
670
+ h(CFormInput, {
671
+ onInput: (e) => {
672
+ handleTableFilterChange(
673
+ (e.target as HTMLInputElement).value,
674
+ 'input',
675
+ )
676
+ },
677
+ onChange: (e) => {
678
+ handleTableFilterChange(
679
+ (e.target as HTMLInputElement).value,
680
+ 'change',
681
+ )
682
+ },
683
+ placeholder: props.tableFilterPlaceholder,
684
+ value: tableFilterState.value,
685
+ }),
686
+ ),
687
+ ],
688
+ },
689
+ ),
649
690
  ),
650
691
  props.cleaner &&
651
692
  h(
@@ -654,22 +695,27 @@ const CSmartTable = defineComponent({
654
695
  class: 'col-auto p-0',
655
696
  },
656
697
  h(
657
- CSmartTableCleaner,
658
- {
659
- onClick: () => clean(),
660
- isFiltered: isFiltered.value,
661
- },
698
+ 'button',
662
699
  {
663
- // @slot Cleaner icon.
664
- cleanerIcon: () =>
665
- slots.cleanerIcon
666
- ? slots.cleanerIcon()
667
- : h(CIcon, { width: '18', content: cilFilterX }),
700
+ type: 'button',
701
+ class: 'btn btn-transparent',
702
+ ...(!(
703
+ tableFilterState.value ||
704
+ sorterState.value.column ||
705
+ Object.values(columnFilterState.value).join('')
706
+ ) && { disabled: true, tabIndex: -1 }),
707
+ onClick: () => handleClean(),
708
+ onKeydown: (event: KeyboardEvent) => {
709
+ if (event.key === 'Enter') handleClean()
710
+ },
668
711
  },
712
+ slots.cleanerIcon
713
+ ? slots.cleanerIcon()
714
+ : h(CIcon, { width: '18', content: cilFilterX }),
669
715
  ),
670
716
  ),
671
717
  ],
672
- ), //h
718
+ ),
673
719
  h(
674
720
  'div',
675
721
  {
@@ -692,20 +738,22 @@ const CSmartTable = defineComponent({
692
738
  ...props.tableHeadProps,
693
739
  columnFilter: props.columnFilter,
694
740
  columnFilterValue: columnFilterState.value,
695
- columns: props.columns ? props.columns : rawColumnNames.value,
741
+ columns: props.columns ? props.columns : columnNames.value,
696
742
  columnSorter: props.columnSorter,
697
743
  items: items.value,
698
744
  selectable: props.selectable,
699
- selectAll: selectedAll.value,
700
- sorterState: sorterState,
745
+ selectAll: props.selectAll,
746
+ selectedAll: selectedAll.value,
747
+ sorterState: sorterState.value,
701
748
  onCustomFilterChange: (key: string, value: any) =>
702
- columnFilterChange(key, value),
749
+ handleColumnFilterChange(key, value),
703
750
  onFilterInput: (key: string, value: string) =>
704
- columnFilterChange(key, value, 'input'),
751
+ handleColumnFilterChange(key, value, 'input'),
705
752
  onFilterChange: (key: string, value: string) =>
706
- columnFilterChange(key, value, 'change'),
753
+ handleColumnFilterChange(key, value, 'change'),
707
754
  onSelectAllChecked: () => handleSelectAllChecked(),
708
- onSortClick: (key: string, index: number) => sorterChange(key, index),
755
+ onSortClick: (key: string, index: number) =>
756
+ handleSorterChange(key, index),
709
757
  },
710
758
  {
711
759
  // @slot Sorter icon when items are unsorted.
@@ -723,8 +771,7 @@ const CSmartTable = defineComponent({
723
771
  sortingIconAscending: () =>
724
772
  slots.sortingIconAscending
725
773
  ? slots.sortingIconAscending()
726
- : // : h(CIcon, { content: cilArrowBottom }, 'b'),
727
- h('svg', {
774
+ : h('svg', {
728
775
  xmlns: 'http://www.w3.org/2000/svg',
729
776
  class: 'icon',
730
777
  viewBox: '0 0 512 512',
@@ -735,8 +782,7 @@ const CSmartTable = defineComponent({
735
782
  sortingIconDescending: () =>
736
783
  slots.sortingIconDescending
737
784
  ? slots.sortingIconDescending()
738
- : // : h(CIcon, { content: cilArrowTop }, 'c'),
739
- h('svg', {
785
+ : h('svg', {
740
786
  xmlns: 'http://www.w3.org/2000/svg',
741
787
  class: 'icon',
742
788
  viewBox: '0 0 512 512',
@@ -746,20 +792,21 @@ const CSmartTable = defineComponent({
746
792
  },
747
793
  ),
748
794
  h(CSmartTableBody, {
795
+ clickableRows: props.clickableRows,
796
+ columnNames: columnNames.value,
749
797
  currentItems: currentItems.value,
750
798
  firstItemOnActivePageIndex: firstItemOnActivePageIndex.value,
751
799
  noItemsLabel: props.noItemsLabel,
752
- scopedSlots: slots,
753
- selectable: props.selectable,
754
- onRowChecked: (id: number, value: boolean) => handleRowChecked(id, value),
800
+ onRowChecked: (item: Item, value: boolean) => handleRowChecked(item, value),
755
801
  onRowClick: (
756
802
  item: Item,
757
803
  index: number,
758
804
  columnName: string,
759
805
  event: MouseEvent | boolean,
760
- ) => handleRowClick(item, index, columnName, event),
761
- rawColumnNames: rawColumnNames.value,
762
- clickableRows: props.clickableRows,
806
+ ) => props.clickableRows && emit('rowClick', item, index, columnName, event),
807
+ scopedSlots: slots,
808
+ selectable: props.selectable,
809
+ selected: selected.value,
763
810
  ...props.tableBodyProps,
764
811
  }),
765
812
  typeof props.footer === 'boolean' &&
@@ -769,9 +816,10 @@ const CSmartTable = defineComponent({
769
816
  ...props.tableFootProps,
770
817
  columnFilter: false,
771
818
  columnSorter: false,
772
- columns: props.columns ? props.columns : rawColumnNames.value,
819
+ columns: props.columns ? props.columns : columnNames.value,
773
820
  selectable: props.selectable,
774
- selectAll: selectedAll.value,
821
+ selectAll: props.selectAll,
822
+ selectedAll: selectedAll.value,
775
823
  onSelectAllChecked: () => handleSelectAllChecked(),
776
824
  }),
777
825
  Array.isArray(props.footer) &&
@@ -810,12 +858,21 @@ const CSmartTable = defineComponent({
810
858
  },
811
859
  ),
812
860
  props.loading &&
813
- h(CElementCover, {
814
- boundaries: [
815
- { sides: ['top'], query: 'tbody' },
816
- { sides: ['bottom'], query: 'tbody' },
817
- ],
818
- }),
861
+ h(
862
+ CElementCover,
863
+ {
864
+ boundaries: [
865
+ { sides: ['top'], query: 'tbody' },
866
+ { sides: ['bottom'], query: 'tbody' },
867
+ ],
868
+ },
869
+ {
870
+ // @slot elementCover.
871
+ ...(slots.elementCover && {
872
+ default: () => slots.elementCover && slots.elementCover(),
873
+ }),
874
+ },
875
+ ),
819
876
  ],
820
877
  },
821
878
  ),
@@ -849,16 +906,56 @@ const CSmartTable = defineComponent({
849
906
  class: 'col-auto ms-auto',
850
907
  },
851
908
  props.itemsPerPageSelect &&
852
- h(CSmartTableItemsPerPageSelector, {
853
- itemsPerPage: itemsPerPage.value,
854
- itemsPerPageLabel: props.itemsPerPageLabel,
855
- itemsPerPageOptions: props.itemsPerPageOptions,
856
- onChangeItemsPerPage: handleItemsPerPageChange,
857
- }),
909
+ h(
910
+ 'div',
911
+ {
912
+ class: 'row',
913
+ },
914
+ {
915
+ default: () => [
916
+ h(
917
+ CFormLabel,
918
+ {
919
+ class: 'col-auto col-form-label',
920
+ },
921
+ {
922
+ default: () => props.itemsPerPageLabel,
923
+ },
924
+ ),
925
+ h(
926
+ 'div',
927
+ {
928
+ class: 'col-auto',
929
+ },
930
+ h(
931
+ CFormSelect,
932
+ {
933
+ value: itemsPerPage.value,
934
+ onChange: handleItemsPerPageChange,
935
+ },
936
+ {
937
+ default: () =>
938
+ props.itemsPerPageOptions &&
939
+ props.itemsPerPageOptions.map((number, index) => {
940
+ return h(
941
+ 'option',
942
+ {
943
+ value: number,
944
+ key: index,
945
+ },
946
+ number,
947
+ )
948
+ }),
949
+ },
950
+ ),
951
+ ),
952
+ ],
953
+ },
954
+ ),
858
955
  ),
859
956
  ],
860
957
  ),
861
- ]) //h
958
+ ])
862
959
  },
863
960
  })
864
961
  export { CSmartTable }