1
- import { defineComponent , h } from 'vue'
1
+ import { computed , defineComponent , h , PropType } from 'vue'
2
2
3
3
import { Color } from '../props'
4
+ import { CTableBody } from './CTableBody'
5
+ import { CTableCaption } from './CTableCaption'
6
+ import { CTableDataCell } from './CTableDataCell'
7
+ import { CTableFoot } from './CTableFoot'
8
+ import { CTableHead } from './CTableHead'
9
+ import { CTableHeaderCell } from './CTableHeaderCell'
10
+ import { CTableRow } from './CTableRow'
11
+
12
+ export interface Column {
13
+ label ?: string
14
+ key : string
15
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
16
+ _style ?: any
17
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
18
+ _props ?: any
19
+ }
20
+
21
+ export interface FooterItem {
22
+ label ?: string
23
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
24
+ _props ?: any
25
+ }
26
+
27
+ export type Item = {
28
+ [ key : string ] : number | string | any
29
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
30
+ _props ?: any
31
+ }
32
+
33
+ const pretifyName = ( name : string ) => {
34
+ return name
35
+ . replace ( / [ - _ . ] / g, ' ' )
36
+ . replace ( / + / g, ' ' )
37
+ . replace ( / ( [ a - z 0 - 9 ] ) ( [ A - Z ] ) / g, '$1 $2' )
38
+ . split ( ' ' )
39
+ . map ( ( word ) => word . charAt ( 0 ) . toUpperCase ( ) + word . slice ( 1 ) )
40
+ . join ( ' ' )
41
+ }
42
+
43
+ const label = ( column : Column | string ) =>
44
+ typeof column === 'object'
45
+ ? column . label !== undefined
46
+ ? column . label
47
+ : pretifyName ( column . key )
48
+ : pretifyName ( column )
4
49
5
50
const CTable = defineComponent ( {
6
51
name : 'CTable' ,
@@ -41,22 +86,61 @@ const CTable = defineComponent({
41
86
/**
42
87
* Put the `<caption>` on the top of the table.
43
88
*
44
- * @values 'top'
89
+ * @values 'top' | string
45
90
*/
46
91
caption : {
47
92
type : String ,
48
93
default : undefined ,
49
94
required : false ,
50
- validator : ( value : string ) => {
51
- return value === 'top'
52
- } ,
95
+ } ,
96
+ /**
97
+ * Set the text of the table caption and the caption on the top of the table.
98
+ *
99
+ * @since 4.5.0
100
+ */
101
+ captionTop : {
102
+ type : String ,
103
+ default : undefined ,
104
+ required : false ,
105
+ } ,
106
+ /**
107
+ * 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')
108
+ *
109
+ * In columns prop each array item represents one column. Item might be specified in two ways:
110
+ * String: each item define column name equal to item value.
111
+ * Object: item is object with following keys available as column configuration:
112
+ * - key (required)(String) - define column name equal to item key.
113
+ * - label (String) - define visible label of column. If not defined, label will be generated automatically based on column name, by converting kebab-case and snake_case to individual words and capitalization of each word.
114
+ * - _props (Object) - adds classes to all cels in column, ex. _props: { scope: 'col', className: 'custom-class' },
115
+ * - _style (Object) - adds styles to the column header (useful for defining widths)
116
+ *
117
+ * @since 4.5.0
118
+ */
119
+ columns : {
120
+ type : Array as PropType < Column [ ] | string [ ] > ,
121
+ required : false ,
53
122
} ,
54
123
/**
55
124
* Sets the color context of the component to one of CoreUI’s themed colors.
56
125
*
57
126
* @values 'primary', 'secondary', 'success', 'danger', 'warning', 'info', 'dark', 'light', string
58
127
*/
59
128
color : Color ,
129
+ /**
130
+ * Array of objects or strings, where each element represents one cell in the table footer.
131
+ *
132
+ * Example items:
133
+ * ['FooterCell', 'FooterCell', 'FooterCell']
134
+ * or
135
+ * [{ label: 'FooterCell', _props: { color: 'success' }, ...]
136
+ *
137
+ * @since 4.5.0
138
+ */
139
+ footer : {
140
+ type : Array as PropType < FooterItem [ ] > ,
141
+ default : ( ) => [ ] ,
142
+ required : false ,
143
+ } ,
60
144
/**
61
145
* Enable a hover state on table rows within a `<CTableBody>`.
62
146
*/
@@ -65,10 +149,18 @@ const CTable = defineComponent({
65
149
required : false ,
66
150
} ,
67
151
/**
68
- * Make any table responsive across all viewports or pick a maximum breakpoint with which to have a responsive table up to .
152
+ * Array of objects, where each object represents one item - row in table. Additionally, you can add style classes to each row by passing them by '_props' key and to single cell by '_cellProps' .
69
153
*
70
- * @values boolean, 'sm', 'md', 'lg', 'xl', 'xxl'
154
+ * Example item:
155
+ * { name: 'John' , age: 12, _props: { color: 'success' }, _cellProps: { age: { className: 'fw-bold'}}}
156
+ *
157
+ * @since 4.5.0
71
158
*/
159
+ items : {
160
+ type : Array as PropType < Item [ ] > ,
161
+ default : ( ) => [ ] ,
162
+ required : false ,
163
+ } ,
72
164
responsive : {
73
165
type : [ Boolean , String ] ,
74
166
default : undefined ,
@@ -106,8 +198,39 @@ const CTable = defineComponent({
106
198
type : Boolean ,
107
199
required : false ,
108
200
} ,
201
+ /**
202
+ * Properties that will be passed to the table footer component.
203
+ *
204
+ * Properties to [CTableFoot](#ctablefoot) component.
205
+ * @since 4.5.0
206
+ */
207
+ tableFootProps : {
208
+ type : Object ,
209
+ default : undefined ,
210
+ required : false ,
211
+ } ,
212
+ /**
213
+ * Properties that will be passed to the table head component.
214
+ *
215
+ * Properties to [CTableHead](#ctablehead) component.
216
+ * @since 4.5.0
217
+ */
218
+ tableHeadProps : {
219
+ type : Object ,
220
+ default : undefined ,
221
+ required : false ,
222
+ } ,
109
223
} ,
110
224
setup ( props , { slots, attrs } ) {
225
+ const rawColumnNames = computed ( ( ) =>
226
+ props . columns
227
+ ? props . columns . map ( ( column : Column | string ) => {
228
+ if ( typeof column === 'object' ) return column . key
229
+ else return column
230
+ } )
231
+ : Object . keys ( props . items [ 0 ] || { } ) . filter ( ( el ) => el . charAt ( 0 ) !== '_' ) ,
232
+ )
233
+
111
234
const table = ( ) =>
112
235
h (
113
236
'table' ,
@@ -116,7 +239,7 @@ const CTable = defineComponent({
116
239
'table' ,
117
240
{
118
241
[ `align-${ props . align } ` ] : props . align ,
119
- [ `caption-${ props . caption } ` ] : props . caption ,
242
+ [ `caption-top ` ] : props . captionTop || props . caption === 'top' ,
120
243
[ `border-${ props . borderColor } ` ] : props . borderColor ,
121
244
'table-bordered' : props . bordered ,
122
245
'table-borderless' : props . borderless ,
@@ -129,7 +252,118 @@ const CTable = defineComponent({
129
252
attrs . class ,
130
253
] ,
131
254
} ,
132
- slots . default && slots . default ( ) ,
255
+ {
256
+ default : ( ) => [
257
+ ( ( props . caption && props . caption !== 'top' ) || props . captionTop ) &&
258
+ h (
259
+ CTableCaption ,
260
+ { } ,
261
+ {
262
+ default : ( ) => props . caption || props . captionTop ,
263
+ } ,
264
+ ) ,
265
+ props . columns &&
266
+ h (
267
+ CTableHead ,
268
+ {
269
+ ...props . tableHeadProps ,
270
+ } ,
271
+ {
272
+ default : ( ) =>
273
+ h (
274
+ CTableRow ,
275
+ { } ,
276
+ {
277
+ default : ( ) => [
278
+ props . columns &&
279
+ props . columns . map ( ( column : Column | string ) =>
280
+ h (
281
+ CTableHeaderCell ,
282
+ {
283
+ ...( typeof column === 'object' &&
284
+ column . _props && { ...column . _props } ) ,
285
+ ...( typeof column === 'object' &&
286
+ column . _style && { style : { ...column . _style } } ) ,
287
+ } ,
288
+ {
289
+ default : ( ) => label ( column ) ,
290
+ } ,
291
+ ) ,
292
+ ) ,
293
+ ] ,
294
+ } ,
295
+ ) ,
296
+ } ,
297
+ ) ,
298
+ props . items &&
299
+ h (
300
+ CTableBody ,
301
+ { } ,
302
+ {
303
+ default : ( ) => [
304
+ props . items . map ( ( item : Item ) =>
305
+ h (
306
+ CTableRow ,
307
+ {
308
+ ...( item . _props && { ...item . _props } ) ,
309
+ } ,
310
+ {
311
+ default : ( ) => [
312
+ rawColumnNames . value . map (
313
+ ( colName : string ) =>
314
+ item [ colName ] &&
315
+ h (
316
+ CTableDataCell ,
317
+ {
318
+ ...( item . _cellProps &&
319
+ item . _cellProps [ 'all' ] && { ...item . _cellProps [ 'all' ] } ) ,
320
+ ...( item . _cellProps &&
321
+ item . _cellProps [ colName ] && { ...item . _cellProps [ colName ] } ) ,
322
+ } ,
323
+ {
324
+ default : ( ) => item [ colName ] ,
325
+ } ,
326
+ ) ,
327
+ ) ,
328
+ ] ,
329
+ } ,
330
+ ) ,
331
+ ) ,
332
+ ] ,
333
+ } ,
334
+ ) ,
335
+ slots . default && slots . default ( ) ,
336
+ props . footer &&
337
+ h (
338
+ CTableFoot ,
339
+ {
340
+ ...props . tableFootProps ,
341
+ } ,
342
+ {
343
+ default : ( ) =>
344
+ h (
345
+ CTableRow ,
346
+ { } ,
347
+ {
348
+ default : ( ) => [
349
+ props . footer . map ( ( item : FooterItem | string ) =>
350
+ h (
351
+ CTableDataCell ,
352
+ {
353
+ ...( typeof item === 'object' && item . _props && { ...item . _props } ) ,
354
+ } ,
355
+ {
356
+ default : ( ) => ( typeof item === 'object' ? item . label : item ) ,
357
+ } ,
358
+ ) ,
359
+ ) ,
360
+ ] ,
361
+ } ,
362
+ ) ,
363
+ } ,
364
+ ) ,
365
+ ] ,
366
+ } ,
133
367
)
134
368
return ( ) => [
135
369
props . responsive
0 commit comments