1
- import { Component , Element , Prop , h , Event , EventEmitter , State } from '@stencil/core' ;
1
+ import {
2
+ Component ,
3
+ Element ,
4
+ Prop ,
5
+ h ,
6
+ Event ,
7
+ EventEmitter ,
8
+ State ,
9
+ } from '@stencil/core' ;
2
10
import classnames from 'classnames' ;
3
11
4
12
/**
@@ -28,8 +36,8 @@ export class VaTableInner {
28
36
@Prop ( ) tableTitle : string ;
29
37
30
38
/*
31
- * The number of rows in the table
32
- */
39
+ * The number of rows in the table
40
+ */
33
41
@Prop ( ) rows ?: number ;
34
42
35
43
/**
@@ -62,11 +70,11 @@ export class VaTableInner {
62
70
*/
63
71
@State ( ) sortindex ?: number = null ;
64
72
65
- /**
73
+ /**
66
74
* Fires when the component is closed by clicking on the close icon. This fires only
67
75
* when closeable is true.
68
76
*/
69
- @Event ( {
77
+ @Event ( {
70
78
composed : true ,
71
79
bubbles : true ,
72
80
} )
@@ -85,7 +93,7 @@ export class VaTableInner {
85
93
const th = target . closest ( 'th' ) ;
86
94
const sortdir = th . dataset . sortdir ;
87
95
const index = th . dataset . rowindex ;
88
- this . sortTable . emit ( { index, sortdir } ) ;
96
+ this . sortTable . emit ( { index, sortdir } ) ;
89
97
}
90
98
91
99
handleKeyDown ( e : KeyboardEvent ) {
@@ -100,21 +108,22 @@ export class VaTableInner {
100
108
if ( this . sortable && row === 0 ) {
101
109
// we just performed a sort on this column
102
110
if ( this . sortindex !== null && this . sortindex === index ) {
103
- const icon_name = this . sortdir == 'descending' ? 'arrow_upward' : 'arrow_downward' ;
104
- icon = < va-icon icon = { icon_name } size = { 3 } />
105
- // we did not just perform a sort on this column
111
+ const icon_name =
112
+ this . sortdir == 'descending' ? 'arrow_upward' : 'arrow_downward' ;
113
+ icon = < va-icon icon = { icon_name } size = { 3 } /> ;
114
+ // we did not just perform a sort on this column
106
115
} else {
107
- icon = < va-icon icon = "sort_arrow" size = { 3 } />
116
+ icon = < va-icon icon = "sort_arrow" size = { 3 } /> ;
108
117
}
109
118
return (
110
119
< button
111
120
tabIndex = { 0 }
112
- onClick = { ( e ) => this . fireSort ( e ) }
113
- onKeyDown = { ( e ) => this . handleKeyDown ( e ) }
121
+ onClick = { e => this . fireSort ( e ) }
122
+ onKeyDown = { e => this . handleKeyDown ( e ) }
114
123
>
115
124
{ icon }
116
125
</ button >
117
- )
126
+ ) ;
118
127
} else {
119
128
return null ;
120
129
}
@@ -124,32 +133,38 @@ export class VaTableInner {
124
133
* Generate the markup for a table row where row is the zero-indexed row number
125
134
*/
126
135
makeRow ( row : number ) : HTMLTableRowElement {
136
+ // Ensure first row <th> are col scoped for screen reader usability
137
+ let scopeDimension = ( row === 0 && 'col' ) || 'row' ;
138
+
127
139
return (
128
140
< tr >
129
141
{ Array . from ( { length : this . cols } ) . map ( ( _ , i ) => {
130
142
const slotName = `va-table-slot-${ row * this . cols + i } ` ;
131
143
const slot = < slot name = { slotName } > </ slot > ;
132
- const header = this . el . querySelector ( `[slot="va-table-slot-${ i } "]` ) . innerHTML ;
144
+ const header = this . el . querySelector (
145
+ `[slot="va-table-slot-${ i } "]` ,
146
+ ) . innerHTML ;
133
147
const dataSortActive = row > 0 && this . sortindex === i ? true : false ;
134
- return ( i === 0 || row === 0 )
135
- ?
148
+ return i === 0 || row === 0 ? (
136
149
< th
137
- scope = "row"
150
+ scope = { scopeDimension }
138
151
data-sortable
139
152
data-sort-active = { dataSortActive }
140
153
data-label = { header }
141
154
data-rowindex = { i }
142
155
data-sortdir = { i === this . sortindex ? this . sortdir : 'ascending' }
143
156
>
144
- { slot } { this . getSortIcon ( i , row ) }
157
+ { slot }
158
+ { this . getSortIcon ( i , row ) }
145
159
</ th >
146
- :
160
+ ) : (
147
161
< td data-label = { header } data-sort-active = { dataSortActive } >
148
162
{ slot }
149
163
</ td >
164
+ ) ;
150
165
} ) }
151
166
</ tr >
152
- )
167
+ ) ;
153
168
}
154
169
155
170
/**
@@ -158,7 +173,7 @@ export class VaTableInner {
158
173
getBodyRows ( ) : HTMLTableRowElement [ ] {
159
174
const rows = [ ] ;
160
175
for ( let i = 1 ; i < this . rows ; i ++ ) {
161
- rows . push ( this . makeRow ( i ) )
176
+ rows . push ( this . makeRow ( i ) ) ;
162
177
}
163
178
return rows ;
164
179
}
@@ -177,7 +192,12 @@ export class VaTableInner {
177
192
178
193
// only runs if sortable is true
179
194
// update the aria-label for a th after a sort
180
- updateThAriaLabel ( th : HTMLTableCellElement , thSorted : boolean , currentSortDirection : string , content : string ) {
195
+ updateThAriaLabel (
196
+ th : HTMLTableCellElement ,
197
+ thSorted : boolean ,
198
+ currentSortDirection : string ,
199
+ content : string ,
200
+ ) {
181
201
let thSortInfo : string ;
182
202
if ( thSorted ) {
183
203
thSortInfo = `currently sorted ${ currentSortDirection } ` ;
@@ -191,7 +211,12 @@ export class VaTableInner {
191
211
192
212
// only runs if sortable is true
193
213
// update the title info on span clicked to sort and focus it
194
- updateSpan ( th : HTMLTableCellElement , thSorted : boolean , nextSortDirection : string , content : string ) {
214
+ updateSpan (
215
+ th : HTMLTableCellElement ,
216
+ thSorted : boolean ,
217
+ nextSortDirection : string ,
218
+ content : string ,
219
+ ) {
195
220
const button = th . querySelector ( 'button' ) ;
196
221
let spanSortInfo = `Click to sort by ${ content } in ${ nextSortDirection } order` ;
197
222
button . setAttribute ( 'title' , spanSortInfo ) ;
@@ -204,26 +229,42 @@ export class VaTableInner {
204
229
205
230
// only runs if sortable is true
206
231
// if a sort has occurred update the sr text to reflect this
207
- updateSRtext ( thSorted : boolean , content : string , currentSortDirection : string ) {
232
+ updateSRtext (
233
+ thSorted : boolean ,
234
+ content : string ,
235
+ currentSortDirection : string ,
236
+ ) {
208
237
if ( thSorted ) {
209
- const tableInfo = ! ! this . tableTitle ? `The table named "${ this . tableTitle } "` : 'This table' ;
210
- this . el . shadowRoot . querySelector ( 'table + div' ) . innerHTML = `${ tableInfo } is now sorted by ${ content } in ${ currentSortDirection } order` ;
238
+ const tableInfo = ! ! this . tableTitle
239
+ ? `The table named "${ this . tableTitle } "`
240
+ : 'This table' ;
241
+ this . el . shadowRoot . querySelector (
242
+ 'table + div' ,
243
+ ) . innerHTML = `${ tableInfo } is now sorted by ${ content } in ${ currentSortDirection } order` ;
211
244
}
212
245
}
213
246
214
247
// only runs if sortable is true
215
248
// for a given th, get the current and the next sort directions
216
- getSortDirections ( ) : { currentSortDirection : string , nextSortDirection : string } {
249
+ getSortDirections ( ) : {
250
+ currentSortDirection : string ;
251
+ nextSortDirection : string ;
252
+ } {
217
253
const nextSortDirection = ! ! this . sortdir ? this . sortdir : 'ascending' ;
218
- const currentSortDirection = nextSortDirection === 'ascending' ? 'descending' : 'ascending' ;
219
- return { currentSortDirection, nextSortDirection }
254
+ const currentSortDirection =
255
+ nextSortDirection === 'ascending' ? 'descending' : 'ascending' ;
256
+ return { currentSortDirection, nextSortDirection } ;
220
257
}
221
258
222
259
// for a sortable table set the state to take into account previous sort
223
260
componentWillLoad ( ) {
224
261
if ( this . sortable ) {
225
- this . sortindex = this . el . dataset . sortindex ? + this . el . dataset . sortindex : this . sortindex ;
226
- this . sortdir = this . el . dataset . sortdir ? this . el . dataset . sortdir : this . sortdir ;
262
+ this . sortindex = this . el . dataset . sortindex
263
+ ? + this . el . dataset . sortindex
264
+ : this . sortindex ;
265
+ this . sortdir = this . el . dataset . sortdir
266
+ ? this . el . dataset . sortdir
267
+ : this . sortdir ;
227
268
}
228
269
}
229
270
@@ -237,27 +278,30 @@ export class VaTableInner {
237
278
if ( this . sortable ) {
238
279
const slots = this . el . shadowRoot . querySelectorAll ( 'slot' ) ;
239
280
// loop through slots inside the table header ths
240
- Array . from ( slots ) . slice ( 0 , this . cols ) . forEach ( ( slot , i ) => {
241
- const th = slot . closest ( 'th' ) ;
281
+ Array . from ( slots )
282
+ . slice ( 0 , this . cols )
283
+ . forEach ( ( slot , i ) => {
284
+ const th = slot . closest ( 'th' ) ;
242
285
243
- // was this th just sorted
244
- const thSorted = this . sortindex !== null && this . sortindex === i ;
286
+ // was this th just sorted
287
+ const thSorted = this . sortindex !== null && this . sortindex === i ;
245
288
246
- // text content of this th
247
- const content = this . getSortColumnText ( slot ) ;
289
+ // text content of this th
290
+ const content = this . getSortColumnText ( slot ) ;
248
291
249
- // get the sort directions of this th
250
- const { currentSortDirection, nextSortDirection } = this . getSortDirections ( ) ;
292
+ // get the sort directions of this th
293
+ const { currentSortDirection, nextSortDirection } =
294
+ this . getSortDirections ( ) ;
251
295
252
- // update aria-label of th to reflect sort
253
- this . updateThAriaLabel ( th , thSorted , currentSortDirection , content ) ;
296
+ // update aria-label of th to reflect sort
297
+ this . updateThAriaLabel ( th , thSorted , currentSortDirection , content ) ;
254
298
255
- // update title info of span inside th to reflect sort
256
- this . updateSpan ( th , thSorted , nextSortDirection , content ) ;
299
+ // update title info of span inside th to reflect sort
300
+ this . updateSpan ( th , thSorted , nextSortDirection , content ) ;
257
301
258
- // update sr text to reflect sort
259
- this . updateSRtext ( thSorted , content , currentSortDirection ) ;
260
- } ) ;
302
+ // update sr text to reflect sort
303
+ this . updateSRtext ( thSorted , content , currentSortDirection ) ;
304
+ } ) ;
261
305
}
262
306
}
263
307
@@ -271,14 +315,12 @@ export class VaTableInner {
271
315
return (
272
316
< div >
273
317
< table class = { classes } >
274
- { tableTitle && < caption > { tableTitle } </ caption > }
275
- < thead > { this . makeRow ( 0 ) } </ thead >
276
- < tbody id = "va-table-body" >
277
- { this . getBodyRows ( ) }
278
- </ tbody >
318
+ { tableTitle && < caption > { tableTitle } </ caption > }
319
+ < thead > { this . makeRow ( 0 ) } </ thead >
320
+ < tbody id = "va-table-body" > { this . getBodyRows ( ) } </ tbody >
279
321
</ table >
280
322
< div class = "usa-sr-only" aria-live = "polite" > </ div >
281
323
</ div >
282
- )
324
+ ) ;
283
325
}
284
326
}
0 commit comments