Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(carousel): improved tab page navigation #5035

Merged

Conversation

IgnacioBecerra
Copy link
Contributor

Related Ticket(s)

#4799

Description

Carousel now moves pages automatically when using tab navigation and focusing on the next card in a different page. Works going forward or backwards.

Changelog

New

  • pages now change dynamically depending on the focused card index

@ibmdotcom-bot
Copy link
Contributor

ibmdotcom-bot commented Jan 28, 2021

@ibmdotcom-bot
Copy link
Contributor

ibmdotcom-bot commented Jan 28, 2021

Copy link
Contributor

@asudoh asudoh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for jumping in @IgnacioBecerra!

Copy link
Contributor

@asudoh asudoh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for trying to update @IgnacioBecerra!

@ibmdotcom-bot
Copy link
Contributor

ibmdotcom-bot commented Jan 29, 2021

Copy link
Contributor

@asudoh asudoh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the update @IgnacioBecerra!

Copy link
Contributor

@asudoh asudoh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for another update @IgnacioBecerra!

Copy link
Contributor

@asudoh asudoh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the update @IgnacioBecerra!

if (currentContains) {
// going forwards, change page depending on card index
if (currentCardIndex >= this.start + this.pageSize) {
this.start = currentCardIndex - (currentCardIndex % this.pageSize);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Considering the following condition:

  • We have many cards in carousel
  • this.start previously was 2
  • Screen size as large as putting 4 cards in a page

And user keeps hitting tab key to reach to the code here. What should happen?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@asudo I see, wasn't aware the this.start could be set by the user. Added an additional calculation where it considers the offset to calculate the right index if this.start isn't a proper multiple of this.pageSize.

Now in the condition you provided this.start will become the index 6 instead of 4 as it was before i.e. the next page will start with the proper card.

@IgnacioBecerra IgnacioBecerra added the package: web components Work necessary for the IBM.com Library web components package label Feb 4, 2021
Copy link
Contributor

@asudoh asudoh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update @IgnacioBecerra!

Comment on lines 138 to 141
const nextStart = currentCardIndex - (currentCardIndex % this.pageSize);
const pageOffset = this.start % this.pageSize;

this.start = nextStart + pageOffset;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably you meant this.start = currentCardIndex? (Though there are some edge cases to consider)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nextStart calculates the correct this.start if the user focuses on a random card (and show its containing page)
pageOffset adds any remainder to the calculation if needed, usually it's just 0 (adds 2 in the previous scenario)

this.start = currentCardIndex only works if we tab forward but doesn't address the "random card focus" case.

Copy link
Contributor

@asudoh asudoh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for clarifying @IgnacioBecerra!

Comment on lines 130 to 133
if (currentContains && oldNotContains && currentCardIndex === 0) {
(this.children[this.start] as HTMLElement).focus();
return;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we still need this logic?

Copy link
Contributor Author

@IgnacioBecerra IgnacioBecerra Feb 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@asudoh Yes, we still need that logic to focus on the current starting card after having tabbed outside the carrousel. Without it, the focus will always go to the first card automatically, out of view. This will focus on the current page's starting card.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, thank you for clarifying - I suggest preserving the "focused card index" in _handleFocus(). It can be done by "old contains but current node contains" detection and preserving event.relatedTarget. In this way we can set this.start according to the index of such "previously focused card".


// going backwards, change page depending on card index
} else if (currentCardIndex < this.start) {
this.start = Math.max(currentCardIndex + 1 - this.pageSize, 0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want to apply your improvement to "page forward" logic to the "page backward" logic here, too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we'd use the same code going in either direction, the previous logic runs in both directions whenever the focus is out of the current page.

Copy link
Member

@kennylam kennylam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@IgnacioBecerra This is looking really good. One thing I'm seeing in the center 8 columns story is when advancing, the pagination happens first – another tab is needed to move focus to the next item. Going back in pages works fine.

Feb-08-2021 08-53-07

@IgnacioBecerra
Copy link
Contributor Author

@kennylam Thanks for the comment! After investigating, I found the issue is caused by --dds--carousel--overflow-hint-size: 0rem;, which places the next card out of the viewport. This causes the browser to make the element scroll into view when focusing on the next (hidden) element, which messes with the pagination view. I've messaged Akira to ask if he knows a workaround for this using HostListener.

@asudoh
Copy link
Contributor

asudoh commented Feb 9, 2021

@kennylam Good catch!

@IgnacioBecerra This is caused by <div class="bx--carousel__scroll-container"> scrolls upon the "scrolling into view" effect as you described. Though it's a bit dirty, looks that we can fix that behavior by handling onscroll event on that <div> and calling event.target.scrollTo(0, 0) there.

Copy link
Contributor

@asudoh asudoh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the update @IgnacioBecerra and the discussion offline!

@@ -107,10 +119,57 @@ class DDSCarousel extends LitElement {
// @ts-ignore
this._observerResizeContainer = new ResizeObserver(this._observeResizeContainer);
this._observerResizeContainer.observe(contentsNode);
containerNode?.addEventListener('scroll', this._handleScrollFocus);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you attach this event listener with lit-html template syntax? In this way we don't need to explicitly remove the event listener.

Comment on lines +150 to +160
if (currentContains && oldNotContains) {
// focus coming from the top
if (currentCardIndex === 0) {
(this.children[this.start] as HTMLElement).focus();

// focus coming from bottom
} else if (currentCardIndex === this._total - 1) {
(this.children[this.start + this.pageSize - 1] as HTMLElement).focus();
}
return;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you elaborate why you think we still need this logic here? I thought the first card automatically gets focus in forward-tab scenario, and last card automatically gets on focus in backward-tab scenario. If it's not the case, could you point out what element gets focus instead in such scenarios?

Copy link
Contributor Author

@IgnacioBecerra IgnacioBecerra Feb 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, we still need this logic because the page will not automatically focus on the first/last card on the current page. The focus actually either goes to the very first card (index 0), or to the very last one, so even if the current page is the right one, the focus will be entirely out of view, and the user would need to keep tabbing/shift+tabbing until it reaches the current page if we don't have the focus() here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for clarifying. My thought is tabbing on the very first card, instead of the first card on the current page, in forward-tab scenario. Similar for backward-scenario. Could you work with the designer to double-check that? Thanks!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@asudoh Discussed with @photodow and confirmed that focusing back on the current page (as it is currently) works best.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @IgnacioBecerra - Please add a comment as such.

Copy link
Contributor

@asudoh asudoh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @IgnacioBecerra for all the updates!

@IgnacioBecerra IgnacioBecerra added the Ready to merge Label for the pull requests that are ready to merge label Feb 12, 2021
@kodiakhq kodiakhq bot merged commit 8ec91ec into carbon-design-system:master Feb 12, 2021
IgnacioBecerra added a commit to IgnacioBecerra/ibm-dotcom-library that referenced this pull request Feb 22, 2021
### Related Ticket(s)
carbon-design-system#4799

### Description

Carousel now moves pages automatically when using tab navigation and focusing on the next card in a different page. Works going forward or backwards.

### Changelog

**New**

- pages now change dynamically depending on the focused card index

<!-- React and Web Component deploy previews are enabled by default. -->
<!-- To enable additional available deploy previews, apply the following -->
<!-- labels for the corresponding package: -->
<!-- *** "package: services": Services -->
<!-- *** "package: utilities": Utilities -->
<!-- *** "package: styles": Carbon Expressive -->
<!-- *** "RTL": React / Web Components (RTL) -->
<!-- *** "feature flag": React / Web Components (experimental) -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
package: web components Work necessary for the IBM.com Library web components package Ready to merge Label for the pull requests that are ready to merge
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants