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

UI Infrastructure: Focus Management #169

Open
2 tasks done
bryphe opened this issue Dec 27, 2018 · 5 comments
Open
2 tasks done

UI Infrastructure: Focus Management #169

bryphe opened this issue Dec 27, 2018 · 5 comments
Labels
A-input Area: Input handling, IME etc. help wanted Extra attention is needed

Comments

@bryphe
Copy link
Member

bryphe commented Dec 27, 2018

Managing focus for text input is critical for useful interactive applications. In general, clicking on a text input should grant it focus. In addition, other elements may be 'focusable' for accessibility, like buttons.

Revery should provide an intuitive, React-like interface for working with focus, that is familiar for web developers using React.

Focus is an inherently stateful concept - for a basic scenario, we can keep track of focus at the node level. Our 'focus manager' could essentially keep track of the focused node via a ref.

Proposal

Internally, we need to:

  • Add a Focus module that keeps track of the actively focused node. When that actively focused node changes, it should dispatch focus and blur events to the respective nodes.

For our Nodes, we need to:

On our JSX side, we need to:

  • Add a tabindex field which, for now, is simply a proxy for whether or not it is focusable. Later, when there is more focus on keyboard accessibility, we can extend this to behave as the browser (ie, for tab-key flow)
  • Add an onFocus and onBlur event for nodes. This should be added to our NodeEvents module and dispatched at the proper time.

This lays the groundwork for a simple focus management story. Once we have this in place, we can start 'funneling' the keyboard input to the focused element. Key for implementing apps that need forms!

Testability

  • Calling .focus on a node without tabindex should not change focus
  • Calling .blur on a node with tabindex should cause no node to have focus
  • Calling .focus on a node with tabindex set should change focus
  • When focus changes, the appropriate events are fired (onBlur is triggered for the previous element, and onFocus is triggered for the new element).
@bryphe bryphe added the help wanted Extra attention is needed label Dec 27, 2018
@WhoAteDaCake
Copy link
Contributor

WhoAteDaCake commented Jan 6, 2019

Hi, I've begun working on this, however, as I am relatively new to ocaml/reason ecosystem, I am not sure how to implement the focus module. So far I have, but that would cause a dependency cycle.

module Make = (T: {type t;}) => {
  let focusedNode: ref(option(Node.node(T.t))) = ref(None);

  let focusOn = (node: Node.node(T.t)) => {
    let _ =
      switch (focusedNode^) {
      | None => ()
      | Some(node) => node#blur()
      };
    focusedNode := Some(node);
  };
};

@WhoAteDaCake
Copy link
Contributor

Would I have to implement a focusable sub-class, make sure node extends it and the use that for type parameters?

@bryphe
Copy link
Member Author

bryphe commented Jan 7, 2019

Thanks a lot for taking this on, @WhoAteDaCake !

That functor looks like a solid start - it looks like it'd be testable. Based on the dependency issue - I'm thinking it'd be nice if the Node didn't need to know about focus management. It could work the following way:

  • The focus module keeps track of the active node
  • Input events get funneled through the Focus module (we could implement a Focus.dispatch - like what we did for Mouse events here:
    let dispatch =
    - that logic finds the element under the cursor, and dispatches a mouse event (bubbling it up) - the focus module would want to do similiar bubbling, but the logic could actually be simpler than the mouse case - it would dispatch against the currently active node, if there is one).
  • We could add Blur and Focus events to NodeEvents
  • Instead of sending a Node object to the ref - we could send a more functional wrapper. This would contain a blur and focus method, which, under the hood, would call to the Focus module. This 'proxying' could be facilitated by wrapping the onRef in NodeEvents

This would decouple the dependency tree - because the node wouldn't need to care about focus management, the only concern the Node would have with regard to focus is respond to Blur and Focus events, and dispatching to the appropriate handler in NodeEvents.

Still a little vague, but hopefully that helps give some ideas. Thanks for thinking about this!

@WhoAteDaCake
Copy link
Contributor

I've open #199 . That implements the basic functionality required for focus management.

@saitonakamura
Copy link
Contributor

Maybe we can update this issue to indicate what's already done and what's missing?
Also, @bryphe , in Testability section first case should be most likely without tabindex instead of with

@glennsl glennsl added the A-input Area: Input handling, IME etc. label Nov 26, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-input Area: Input handling, IME etc. help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

4 participants