Open bryphe opened 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);
};
};
Would I have to implement a focusable sub-class, make sure node extends it and the use that for type parameters?
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:
focus
module keeps track of the active nodeFocus
module (we could implement a Focus.dispatch
- like what we did for Mouse
events here: https://github.com/revery-ui/revery/blob/2ec9ecb7f9bd68f6d283276c346dbbac29e5ea8f/src/UI/Mouse.re#L88 - 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).Blur
and Focus
events to NodeEvents
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!
I've open #199 . That implements the basic functionality required for focus management.
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
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 aref
.Proposal
Internally, we need to:
Focus
module that keeps track of the actively focused node. When that actively focused node changes, it should dispatchfocus
andblur
events to the respective nodes.For our Nodes, we need to:
.focus()
and.blur()
methods. These would be available via theref
introduced in https://github.com/revery-ui/revery/pull/139On our JSX side, we need to:
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)onFocus
andonBlur
event for nodes. This should be added to ourNodeEvents
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
.focus
on a node withouttabindex
should not change focus.blur
on a node withtabindex
should cause no node to have focus.focus
on a node withtabindex
set should change focusonBlur
is triggered for the previous element, andonFocus
is triggered for the new element).