microsoft / fluentui-react-native

A react-native component library that implements the Fluent Design System.
https://developer.microsoft.com/fluentui
MIT License
1.25k stars 161 forks source link

Add `SyntheticFocusManager` class for faking focus on FURN components #3691

Closed lawrencewin closed 1 month ago

lawrencewin commented 1 month ago

Platforms Impacted

Description of changes

When implementing a component, such as a combobox, there is a need to allow keyboard navigation while native focus is locked to a certain UI element. In the combobox case, a user needs to be able to navigate between dropdown items while focus is locked to the textbox element.

This PR implements a class, SyntheticFocusManager that can be passed to a component and allows visual focus to rendered and switched between FURN components. all while native focus remains locked to a different element. Currently, compatibility is limited to the TabList component, but the goal is for more compatibility to be locked for other needed FURN components.

Verification

https://github.com/user-attachments/assets/b1c0cf82-8ace-4c04-a450-62fae8e565e9

Pull request checklist

This PR has considered (when applicable):

Saadnajmi commented 1 month ago

EDIT: Apple HIG changed from when I last looked at it. Maybe this is better, I need to find a canonical guide: https://www.w3.org/WAI/ARIA/apg/practices/keyboard-interface/#kbd_focus_vs_selection . The basic idea is that components like lists and comboboxes (where multiple elements exist) will have a "selection" state, so that the main element keeps focus, and keyboard events move selection / which inner element is intractable. There's no general way to do that AFAIK, so it needs to be a per control basis. I like having a SyntheticFocusManager help with that, though I might personally name it "SelectionManager".

Isn't this basically the difference between focus and selection? https://developer.apple.com/design/human-interface-guidelines/focus-and-selection (Apple docs, but I think the general distinction applies cross platform) As in, we can call "synthetic focus" selection, and incorporate that as a state that FURN components can take?

PPatBoyd commented 1 month ago

[discussion] Oooh, neat -- I'm definitely in favor of having ergonomic components that ease implementing accessibilityControls-qualifying UI patterns, they're annoying to get right (@ mention dropdown, ahhhh)

I'm intrigued by how this will show up in the accessibility tree and be handled by styling with regards to [real] focus, [synthetic] focus, and selection -- small bikeshedding opportunity where Apple refers to [synthetic] focus as highlighted.

Inside useTab.win32 I see that it's mapping the SyntheticFocus changes to Focus/Blur state though it seems you're looking at supporting additional UI patterns long-term -- are these patterns in your longer vision?

Along these lines I'm wondering if the SyntheticFocus state should be kept distinct from Focus state, and alignment between the styles for each state be managed by the component? If an outside controlling component is directing this state I'd wonder if the "SyntheticFocusable" capability could be written as a higher-order component to avoid requiring components that should be synthetically-focusable from needing to directly integrate with the FURN SyntheticFocusManager 🤔

Thoughts?

lawrencewin commented 1 month ago

For this example with the TabList, "selection" refers to changing which Tab is indicated by the underline. Having the synthetic focus we want be referred to as "selection" seems confusing in this case, though a "highlight" state mentioned by pat is interesting.

Inside useTab.win32 I see that it's mapping the SyntheticFocus changes to Focus/Blur state though it seems you're looking at supporting additional UI patterns long-term -- are these patterns in your longer vision?

  • SyntheticFocus === Selection

    • ComboBox, @ Mention dropdowns
  • SyntheticFocus !== Selection

    • single-state containers e.g. current tablist
  • SyntheticFocus stacks with Selection state

    • multi-select containers

I haven't thought about other UI patterns in the long term because this is a customer ask for a specific feature. The goal is to be closest to #2, but I'd like to leave flexibility to support those additional patterns. I'm also interested in exploring the HOC approach to integrate the synthetic focus functionality in existing FURN components.

lawrencewin commented 1 month ago

Closing for now due to a lack of need from a partner