-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Add useTabs / Tabs Component #837
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
Conversation
| } | ||
|
|
||
|
|
||
| export class TabsKeyboardDelegate<T> implements KeyboardDelegate { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks like this delegate won't do wrapping, should tabs keyboard navigation do wrapping? @devongovett do you know the answer to this?
If so, you can probably borrow the logic from ActionButtons, https://github.com/adobe/react-spectrum/blob/main/packages/@react-aria/actiongroup/src/ActionGroupKeyboardDelegate.ts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 to the above. Looking at https://www.w3.org/TR/wai-aria-practices-1.2/#keyboard-interaction-20, focus wrapping should be supported IMO. The ActionGroupKeyboardDelegate logic will also solve the direction flipping that happens in RTL locales
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that needs to be up to the delegate. We have the shouldFocusWrap option to useSelectableList that should handle it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we could also consider merging this into ListKeyboardDelegate since it's pretty similar. We'd need to add the orientation option, as well as options to disable typeahead and page up/page down I guess.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That should work too, I guess we would need to add the existing shouldFocusWrap logic in useSelectableCollection to ArrowLeft and ArrowRight right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@so99ynoodles If I am interpreting @devongovett comment correctly (feel free to correct me if I am misunderstanding @devongovett ) I think the focus wrapping should solely be handled by useSelectableCollection via the shouldFocusWrap option. As of now, this keyboard delegate actually handles focus wrapping independently of useSelectableCollection due to how getNextKey and getPreviousKey work (namely
react-spectrum/packages/@react-aria/tabs/src/TabsKeyboardDelegate.ts
Lines 84 to 86 in e56351a
| if (!key) { | |
| key = this.collection.getFirstKey(); | |
| } |
react-spectrum/packages/@react-aria/tabs/src/TabsKeyboardDelegate.ts
Lines 94 to 96 in e56351a
| if (!key) { | |
| key = this.collection.getLastKey(); | |
| } |
Thinking out loud, I think the next change would be to do the following:
- remove
getNextKeyandgetPreviousKeyfrom TabsKeyboardDelegate - replace
this.getNextKey(key)withthis.collection.getKeyAfter(key)andthis.getPreviousKey(key)with `this.collection.getKeyBefore(key) - Add the same
shouldFocusWraplogic that exists inuseSelectableCollectionforArrowUpandArrowDowntoArrowLeftandArrowRight - Ugh, some of the directional stuff gets hairy with
getFirstKeyandgetLastKeyhere, perhaps useSelectableCollection needsflipDirectioncommunicated to it? I'll need to think about this more
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Heh, well... appears all that was copied from ActionGroupKeyboardDelegate so we'd need to change that one too. Perhaps this could be done as a separate task from this PR? Combine all the keyboard delegates into ListKeyboardDelegate.
LFDanLu
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added some comments regarding the aria hook parts of your code. Can comment on the spectrum component parts if you are interested but figured we should focus on the aria bits first. Great work so far btw :)
| } | ||
|
|
||
|
|
||
| export class TabsKeyboardDelegate<T> implements KeyboardDelegate { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that needs to be up to the delegate. We have the shouldFocusWrap option to useSelectableList that should handle it.
| } | ||
|
|
||
|
|
||
| export class TabsKeyboardDelegate<T> implements KeyboardDelegate { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we could also consider merging this into ListKeyboardDelegate since it's pretty similar. We'd need to add the orientation option, as well as options to disable typeahead and page up/page down I guess.
|
@devongovett @LFDanLu @snowystinger Fixed
Testing (Want advice)
|
| useEffect(() => { | ||
| let tabs: HTMLElement[] = Array.from(ref.current.querySelectorAll('.' + styles['spectrum-Tabs-item'])); | ||
| if (overflowMode === 'scrolling') { | ||
| setSelectedTab(tabs.find(tab => tab.dataset.key === state.selectedKey)); | ||
| } | ||
| if (overflowMode === 'dropdown') { | ||
| setSelectedTab(tabs[0]); | ||
| } | ||
| }, [props.children, state.selectedKey, overflowMode]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With regards to the overflow mode you've implemented here is some code that might be of interest: https://github.com/adobe/react-spectrum/blob/main/packages/@react-spectrum/breadcrumbs/src/Breadcrumbs.tsx#L56-L120. Breadcrumbs does some overflow handling that maybe of use. Not a hard requirement for this pull, just putting it here if you are interested, you can play around with how it works here: https://react-spectrum.adobe.com/react-spectrum/Breadcrumbs.html#visible-items-overflow-behavior
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tabs is a bit different though. As soon as any tab doesn't fit, then all tabs collapse into a dropdown, whereas with breadcrumbs, they collapse one by one. We'll need to verify this behavior with the Spectrum design team though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll remove this from this PR and cover it in another PR! Thank you.
devongovett
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good! 😄
| useEffect(() => { | ||
| let tabs: HTMLElement[] = Array.from(ref.current.querySelectorAll('.' + styles['spectrum-Tabs-item'])); | ||
| if (overflowMode === 'scrolling') { | ||
| setSelectedTab(tabs.find(tab => tab.dataset.key === state.selectedKey)); | ||
| } | ||
| if (overflowMode === 'dropdown') { | ||
| setSelectedTab(tabs[0]); | ||
| } | ||
| }, [props.children, state.selectedKey, overflowMode]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tabs is a bit different though. As soon as any tab doesn't fit, then all tabs collapse into a dropdown, whereas with breadcrumbs, they collapse one by one. We'll need to verify this behavior with the Spectrum design team though.
|
@so99ynoodles awesome work! What do you think about merging an initial implementation and then following up in separate PRs for additional features like overflow mode? Seems like that could help keep the PR to a good size. The next step would be adding some tests. We use react-testing-library and Jest. You can check out some of the existing tests for other components to see how they're written. They don't have to be 100% complete for the first merge, but it would be good to start with a few basic ones. Let us know if you have questions! |
|
@devongovett
Do you want me to add tests to this PR? |
|
@so99ynoodles a few tests to cover the basics would be great! We can add more later on. |
|
@devongovett |
devongovett
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great! Thanks so much. 😄
|
Hey @devongovett , |
|
@darekkay its still in alpha right now, but we will have docs once a stable versions ships (hopefully soon!). |
Closes #784
✅ Pull Request Checklist:
📝 Test Instructions:
useTabs/useTabat react-spectrum. But there is a problem I'm getting stuck on. You can ignore those components since they are for demo.🧢 Your Project: