@@ -23,6 +23,9 @@ import styles from './masthead.scss';
23
23
const { prefix } = settings ;
24
24
const { stablePrefix : ddsPrefix } = ddsSettings ;
25
25
26
+ // button gradient width size
27
+ const buttonGradientWidth = 8 ;
28
+
26
29
/**
27
30
* @param a An array.
28
31
* @param predicate The callback function.
@@ -199,30 +202,43 @@ class DDSTopNav extends StableSelectorMixin(HostListenerMixin(BXHeaderNav)) {
199
202
// If the right-side intersection sentinel is in the view, it means that right-side caret button is hidden.
200
203
// Given scrolling to left makes it shown,
201
204
// `contentContainerNode!.offsetWidth` will shrink as we scroll and we need to adjust for it.
202
- const caretRightNodeWidthAdjustment = isIntersectionRightTrackerInContent ? caretRightNode ! . offsetWidth : 0 ;
205
+
203
206
const elems = slotNode ?. assignedElements ( ) as HTMLElement [ ] ;
204
207
if ( elems ) {
205
208
if ( pageIsRTL ) {
209
+ const caretLeftNodeWidthAdjustment = this . _isIntersectionLeftTrackerInContent ? caretLeftNode ! . offsetWidth : 0 ;
206
210
const navRight = navNode ! . getBoundingClientRect ( ) . right ;
207
211
const lastVisibleElementIndex = elems . findIndex (
208
- elem => elem . getBoundingClientRect ( ) . left < navRight - currentScrollPosition - caretRightNodeWidthAdjustment
212
+ elem => elem . getBoundingClientRect ( ) . left < navRight - currentScrollPosition - caretRightNode ! . offsetWidth
209
213
) ;
210
214
if ( lastVisibleElementIndex >= 0 ) {
211
- this . _currentScrollPosition =
215
+ this . _currentScrollPosition = Math . max (
212
216
navRight -
213
- elems [ lastVisibleElementIndex ] . getBoundingClientRect ( ) . left -
214
- contentContainerNode ! . offsetWidth +
215
- caretRightNode ! . offsetWidth ;
217
+ elems [ lastVisibleElementIndex ] . getBoundingClientRect ( ) . left -
218
+ contentContainerNode ! . offsetWidth +
219
+ caretLeftNodeWidthAdjustment +
220
+ caretRightNode ! . offsetWidth +
221
+ buttonGradientWidth ,
222
+ 0
223
+ ) ;
216
224
}
217
225
} else {
226
+ const caretRightNodeWidthAdjustment = isIntersectionRightTrackerInContent
227
+ ? caretRightNode ! . offsetWidth + buttonGradientWidth
228
+ : buttonGradientWidth ;
229
+ const caretLeftNodeWidthAdjustment = this . _isIntersectionLeftTrackerInContent
230
+ ? caretLeftNode ! . offsetWidth + buttonGradientWidth
231
+ : 0 ;
218
232
const navLeft = navNode ! . getBoundingClientRect ( ) . left ;
219
233
const lastVisibleElementIndex = findLastIndex (
220
234
elems ,
221
235
elem => elem . getBoundingClientRect ( ) . left - navLeft < currentScrollPosition
222
236
) ;
223
237
if ( lastVisibleElementIndex >= 0 ) {
224
238
const lastVisibleElementRight = elems [ lastVisibleElementIndex ] . getBoundingClientRect ( ) . right - navLeft ;
225
- const newScrollPosition = lastVisibleElementRight - ( contentContainerNode ! . offsetWidth - caretRightNodeWidthAdjustment ) ;
239
+ const newScrollPosition =
240
+ lastVisibleElementRight -
241
+ ( contentContainerNode ! . offsetWidth + caretLeftNodeWidthAdjustment - caretRightNodeWidthAdjustment ) ;
226
242
// If the new scroll position is less than the width of the left caret button,
227
243
// it means that hiding the left caret button reveals the whole of the left-most nav item.
228
244
// Snaps the left-most nav item to the left edge of nav container in this case.
@@ -247,39 +263,92 @@ class DDSTopNav extends StableSelectorMixin(HostListenerMixin(BXHeaderNav)) {
247
263
_pageIsRTL : pageIsRTL ,
248
264
_slotNode : slotNode ,
249
265
} = this ;
250
- const caretLeftNodeWidthAdjustment = isIntersectionLeftTrackerInContent ? caretLeftNode ! . offsetWidth : 0 ;
251
- const caretRightNodeWidthAdjustment = caretRightNode ! . offsetWidth ;
252
266
const interimLeft = currentScrollPosition + contentContainerNode ! . offsetWidth ;
253
267
const elems = slotNode ?. assignedElements ( ) as HTMLElement [ ] ;
254
268
if ( elems ) {
255
269
if ( pageIsRTL ) {
256
270
const navRight = navNode ! . getBoundingClientRect ( ) . right ;
257
271
const firstVisibleElementIndex = elems . findIndex (
258
- elem => navRight - elem . getBoundingClientRect ( ) . left > interimLeft - caretRightNodeWidthAdjustment
272
+ elem => navRight - elem . getBoundingClientRect ( ) . left > interimLeft - caretLeftNode ! . offsetWidth - buttonGradientWidth
259
273
) ;
260
274
if ( firstVisibleElementIndex > 0 ) {
261
275
const firstVisibleElementLeft = Math . abs (
262
- elems [ firstVisibleElementIndex ] . getBoundingClientRect ( ) . right - navRight + caretRightNodeWidthAdjustment
276
+ elems [ firstVisibleElementIndex ] . getBoundingClientRect ( ) . right -
277
+ navRight +
278
+ caretLeftNode ! . offsetWidth +
279
+ buttonGradientWidth
263
280
) ;
264
281
const maxLeft = contentNode ! . scrollWidth - contentContainerNode ! . offsetWidth ;
265
282
this . _currentScrollPosition = Math . min ( firstVisibleElementLeft , maxLeft ) ;
266
283
}
267
284
} else {
285
+ const caretLeftNodeWidthAdjustment = isIntersectionLeftTrackerInContent ? caretLeftNode ! . offsetWidth : 0 ;
268
286
const navLeft = navNode ! . getBoundingClientRect ( ) . left ;
269
287
const firstVisibleElementIndex = elems . findIndex ( elem => elem . getBoundingClientRect ( ) . right - navLeft > interimLeft ) ;
270
288
if ( firstVisibleElementIndex > 0 ) {
271
- const firstVisibleElementLeft = elems [ firstVisibleElementIndex ] . getBoundingClientRect ( ) . left - navLeft ;
289
+ const firstVisibleElementLeft =
290
+ elems [ firstVisibleElementIndex ] . getBoundingClientRect ( ) . left - navLeft - buttonGradientWidth ;
272
291
// Ensures that is there is no blank area at the right hand side in scroll area
273
292
// if we see the right remainder nav items can be contained in a page
274
293
const maxLeft =
275
294
contentNode ! . scrollWidth -
276
- ( contentContainerNode ! . offsetWidth - caretLeftNodeWidthAdjustment + caretRightNodeWidthAdjustment ) ;
295
+ ( contentContainerNode ! . offsetWidth - caretLeftNodeWidthAdjustment + caretRightNode ! . offsetWidth ) ;
277
296
this . _currentScrollPosition = Math . min ( firstVisibleElementLeft , maxLeft ) ;
278
297
}
279
298
}
280
299
}
281
300
}
282
301
302
+ protected _handleOnKeyDown ( event : KeyboardEvent ) {
303
+ const target = event . target as HTMLAnchorElement ;
304
+ const {
305
+ _pageIsRTL : pageIsRTL ,
306
+ _navNode : navNode ,
307
+ _currentScrollPosition : currentScrollPosition ,
308
+ _contentContainerNode : contentContainerNode ,
309
+ _caretRightNode : caretRightNode ,
310
+ } = this ;
311
+ if ( target ) {
312
+ if ( pageIsRTL ) {
313
+ if ( event . key === 'Tab' ) {
314
+ if ( event . shiftKey ) {
315
+ if (
316
+ target . previousElementSibling &&
317
+ caretRightNode &&
318
+ target . previousElementSibling . getBoundingClientRect ( ) . right + currentScrollPosition >
319
+ navNode ! . getBoundingClientRect ( ) . right - caretRightNode . offsetWidth
320
+ ) {
321
+ this . _paginateLeft ( ) ;
322
+ }
323
+ } else if (
324
+ target . nextElementSibling &&
325
+ caretRightNode &&
326
+ navNode ! . getBoundingClientRect ( ) . right - target . nextElementSibling . getBoundingClientRect ( ) . left >
327
+ currentScrollPosition + contentContainerNode ! . offsetWidth - caretRightNode . offsetWidth
328
+ ) {
329
+ this . _paginateRight ( ) ;
330
+ }
331
+ }
332
+ } else if ( event . key === 'Tab' ) {
333
+ if ( event . shiftKey ) {
334
+ if (
335
+ target . previousElementSibling &&
336
+ target . previousElementSibling . getBoundingClientRect ( ) . left - navNode ! . getBoundingClientRect ( ) . left <
337
+ currentScrollPosition
338
+ ) {
339
+ this . _paginateLeft ( ) ;
340
+ }
341
+ } else if (
342
+ target . nextElementSibling &&
343
+ Math . floor ( target . nextElementSibling . getBoundingClientRect ( ) . right - navNode ! . getBoundingClientRect ( ) . left ) >
344
+ currentScrollPosition + contentContainerNode ! . offsetWidth
345
+ ) {
346
+ this . _paginateRight ( ) ;
347
+ }
348
+ }
349
+ }
350
+ }
351
+
283
352
/**
284
353
* Handles toggle event from the search component.
285
354
*
@@ -329,6 +398,7 @@ class DDSTopNav extends StableSelectorMixin(HostListenerMixin(BXHeaderNav)) {
329
398
_paginateLeft : paginateLeft ,
330
399
_paginateRight : paginateRight ,
331
400
_pageIsRTL : pageIsRTL ,
401
+ _handleOnKeyDown : handleOnKeyDown ,
332
402
} = this ;
333
403
const caretLeftContainerClasses = classMap ( {
334
404
[ `${ prefix } --header__nav-caret-left-container` ] : true ,
@@ -366,7 +436,7 @@ class DDSTopNav extends StableSelectorMixin(HostListenerMixin(BXHeaderNav)) {
366
436
class ="${ prefix } --header__menu-bar "
367
437
aria-label ="${ ifNonNull ( this . menuBarLabel ) } "
368
438
>
369
- < slot > </ slot >
439
+ < slot @keydown =" ${ handleOnKeyDown } " > </ slot >
370
440
</ ul >
371
441
< div class ="${ prefix } --sub-content-left "> </ div >
372
442
</ nav >
@@ -408,7 +478,7 @@ class DDSTopNav extends StableSelectorMixin(HostListenerMixin(BXHeaderNav)) {
408
478
class ="${ prefix } --header__menu-bar "
409
479
aria-label ="${ ifNonNull ( this . menuBarLabel ) } "
410
480
>
411
- < slot > </ slot >
481
+ < slot @keydown =" ${ handleOnKeyDown } " > </ slot >
412
482
</ ul >
413
483
< div class ="${ prefix } --sub-content-right "> </ div >
414
484
</ nav >
0 commit comments