-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
feat: Tabs collapse behaviour #7202
Conversation
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.
Partial review, will finish Monday
let tab: HTMLElement | null = tablistRef.current.querySelector('[role=tab][data-selected=true]'); | ||
|
||
if (tab != null) { | ||
setSelectedTab(tab); | ||
} | ||
} else if (tablistRef?.current) { | ||
let picker: HTMLElement | null = tablistRef.current.querySelector('button'); |
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 forget if aria disallows it, but is the picker guaranteed to be the only button element in the tablist? I don't see children presentation
for the tablist in the spec
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.
yeah, the role tablist doesn't allow for anything other than tabs, I may need to switch the role when we collapse now that you bring it up...
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 just looked at S1 Tabs, looks like we don't change the role of the picker but I see in https://w3c.github.io/aria/#tablist does explicitly state "tab" as the only allowed child role like you mentioned... cc @majornista
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.
@majornista thoughts?
# Conflicts: # packages/@react-spectrum/s2/stories/Tabs.stories.tsx
# Conflicts: # packages/@react-spectrum/s2/package.json # yarn.lock
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.
LGTM
# Conflicts: # packages/@react-spectrum/s2/src/Tabs.tsx
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.
Approving for testing, happy for the rest to be followup
// need to determine the best way to handle icon only -> icon and text | ||
// good enough to aria-label the picker item? |
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.
An interesting situation can happen with the icon only tabs: if you collapse https://reactspectrum.blob.core.windows.net/reactspectrum/777f4b761ccd6a3e45cbdd9d8ee4d623ee6e3516/storybook-s2/index.html?path=/story/tabs--icons&providerSwitcher-locale=he-IL, you will never be able to see the full contents of two of the options because the point of collapse for the icon only tabs is too small. This maybe partially mitigated by the work you are doing to support tooltips on collection items, but maybe this means we should only render the icon of the tab even when it is collapsed but display the full text in the menu dropdown like it already does. Alternatively, we could instead just have the text truncate so it doesn't get cut off
Happy for this to be followup and for others to weigh in.
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 quite follow, are you talking about how the picker shows the label and runs off the overflow area? So the picker should only have the icon?
here's the two options I was trying to decide between
The reason I went the direction I did was so it would more easily label, but I could change it to have the display none text aria-label the icon possibly.
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.
Yep, you basically got the gist of it, essentially the user doesn't have a great way of seeing the selected tab's full text other than opening the dropdown. IMO option 2 that you show above isn't too bad for sighted users since the non collapsed tabs already didn't show the tab's text and aria-labeling would work for screen reader users.
); | ||
} | ||
|
||
function isAllTabsDisabled<T>(collection: Collection<Node<T>> | undefined, disabledKeys: Set<Key>) { |
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.
Interesting that the selectionManager/collection can't help in a case like this where the individual items might be disabled. Maybe worth making RAC tabs return this info in the render props or something
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.
mmm possibly
yeah, the selectionManager is unaware of it, the collection could do it, but I'm not sure if it should because 'all' is a little subjective to the collection being async or not
it'd be more like, 'all currently included items disabled' or something
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.
yep, perhaps something we can discuss/handle as a follow up if others using RAC tabs find themselves needing similar logic
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.
Didn't notice this before, but it seems like focus is lost if you keyboard select an option from the tab picker menu. Also getting warning about missing a heading in the console
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.
huh... i swear i tested this, however, it looks broken in every commit since I added the picker, so not sure what happened. looking into it
focusscope thinks it's restoring to the correct element, the trigger remains in the dom...
ah, react-aria-focus-scope-restore is preventing default off in useSelectableCollection for the tablist, but it doesn't know how to focus the picker
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.
ok, i've addressed it in Tabs, not sure if it should be addressed further down
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.
oh interesting, doesn't feel like useSelectableCollection should be preventing default in this case. Might be the same issue mentioned here: #6451 (comment), lets discuss in a follow up
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.
small comments which can be follow-up
5caf3ea
## API Changes
@react-spectrum/s2/@react-spectrum/s2:Tabs Tabs {
UNSAFE_className?: string
UNSAFE_style?: CSSProperties
aria-describedby?: string
aria-details?: string
aria-label?: string
aria-labelledby?: string
children?: ReactNode
defaultSelectedKey?: Key
density?: 'compact' | 'regular' = 'regular'
disabledKeys?: Iterable<Key>
+ iconOnly?: boolean
id?: string
isDisabled?: boolean
keyboardActivation?: 'automatic' | 'manual' = 'automatic'
onSelectionChange?: (Key) => void
selectedKey?: Key | null
slot?: string | null
styles?: StylesPropWithHeight
} /@react-spectrum/s2:TabList TabList <T extends {}> {
UNSAFE_className?: string
UNSAFE_style?: CSSProperties
aria-describedby?: string
aria-details?: string
aria-label?: string
aria-labelledby?: string
- children?: ReactNode
+ children?: ReactNode | (T) => ReactNode
dependencies?: Array<any>
items?: Iterable<T>
styles?: StylesProp
} /@react-spectrum/s2:Tab Tab {
UNSAFE_className?: string
UNSAFE_style?: CSSProperties
aria-describedby?: string
aria-details?: string
aria-label?: string
aria-labelledby?: string
- children?: ReactNode
+ children: ReactNode
download?: boolean | string
href?: Href
hrefLang?: string
id?: Key
onHoverChange?: (boolean) => void
onHoverEnd?: (HoverEvent) => void
onHoverStart?: (HoverEvent) => void
ping?: string
referrerPolicy?: HTMLAttributeReferrerPolicy
rel?: string
routerOptions?: RouterOptions
styles?: StylesProp
target?: HTMLAttributeAnchorTarget
} /@react-spectrum/s2:TabsProps TabsProps {
UNSAFE_className?: string
UNSAFE_style?: CSSProperties
aria-describedby?: string
aria-details?: string
aria-label?: string
aria-labelledby?: string
children?: ReactNode
defaultSelectedKey?: Key
density?: 'compact' | 'regular' = 'regular'
disabledKeys?: Iterable<Key>
+ iconOnly?: boolean
id?: string
isDisabled?: boolean
keyboardActivation?: 'automatic' | 'manual' = 'automatic'
onSelectionChange?: (Key) => void
selectedKey?: Key | null
slot?: string | null
styles?: StylesPropWithHeight
} /@react-spectrum/s2:TabProps TabProps {
UNSAFE_className?: string
UNSAFE_style?: CSSProperties
aria-describedby?: string
aria-details?: string
aria-label?: string
aria-labelledby?: string
- children?: ReactNode
+ children: ReactNode
download?: boolean | string
href?: Href
hrefLang?: string
id?: Key
onHoverChange?: (boolean) => void
onHoverEnd?: (HoverEvent) => void
onHoverStart?: (HoverEvent) => void
ping?: string
referrerPolicy?: HTMLAttributeReferrerPolicy
rel?: string
routerOptions?: RouterOptions
styles?: StylesProp
target?: HTMLAttributeAnchorTarget
} /@react-spectrum/s2:TabListProps TabListProps <T> {
UNSAFE_className?: string
UNSAFE_style?: CSSProperties
aria-describedby?: string
aria-details?: string
aria-label?: string
aria-labelledby?: string
- children?: ReactNode
+ children?: ReactNode | (T) => ReactNode
dependencies?: Array<any>
items?: Iterable<T>
styles?: StylesProp
} |
* Revert "chore: Update JSDocs and apis for release (#7595)" This reverts commit 101d077. * Revert "fix: Tabs infinite loop (#7487)" This reverts commit 8228e4e. * Revert "fix: Tabs from testing (#7463)" This reverts commit 494e01c. * Revert "feat: Tabs collapse behaviour (#7202)" This reverts commit cd4da2b. * add stuff back that we still want * update lock
Closes
✅ Pull Request Checklist:
📝 Test Instructions:
🧢 Your Project: