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