revery-ui / revery

:zap: Native, high-performance, cross-platform desktop apps - built with Reason!
https://www.outrunlabs.com/revery/
MIT License
8.07k stars 196 forks source link

UI Infrastructure: Focus Management #169

Open bryphe opened 5 years ago

bryphe commented 5 years ago

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:

For our Nodes, we need to:

On our JSX side, we need to:

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

WhoAteDaCake commented 5 years ago

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 commented 5 years ago

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

bryphe commented 5 years ago

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:

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 commented 5 years ago

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

saitonakamura commented 5 years ago

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