NoriginMedia / react-spatial-navigation

DEPRECATED. HOC-based Spatial Navigation. NEW Hooks version is available here: https://github.com/NoriginMedia/norigin-spatial-navigation
MIT License
226 stars 64 forks source link

[Question] Are keydown events queued while spatial navigation is paused? #28

Closed shirakaba closed 4 years ago

shirakaba commented 5 years ago

I'm developing for Web in this case. Here's the situation:

  1. I have a video player screen;
  2. After ten seconds, the UI controls disappear and stop obstructing the full-screen video. I pause spatial navigation now that there are no focusable components on screen;
  3. I receive a 'left' button press, and so I reveal the UI controls again;
  4. I unpause spatial navigation as soon as the UI controls have reappeared.

However, the 'left' navigation action still took place. In order to stop it, I need to call keyEvent.preventDefault() and keyEvent.stopPropagation() while spatial navigation is paused. This behaviour looked to me like Spatial Navigation was queuing these key events and handling them upon unpause; does it do that, or am I probably just misunderstanding something in my own setup?

asgvard commented 5 years ago

Hi, I believe we had the similar problem. We had exactly the same use case. When controls are hidden, we pause the navigation. Then when we press any key, we show controls, and then resume navigation. But perhaps because the spatial navigation listener is on the "window" level, it might catch those key events before it was properly resumed. We solved this with setting 0 timeout to only resume navigation on next animation frame, and not synchronously:

setTimeout(this.props.resumeSpatialNavigation, 0);

Sounds like a hack, but unfortunately didn't have more time to investigate it deeper. The library does not explicitly queue any events though. Perhaps this is due to event bubbling.

shirakaba commented 5 years ago

Glad I'm not imagining it and that it reproduces in another codebase.

I won't have any time to investigate it any time soon, either, unfortunately. Ideally we'd want to implement a solution that transparently handles the event in a sensible way.

shirakaba commented 4 years ago

I've investigated it a bit. React Spatial Navigation listens for key events on window, while my app itself listens for key events on window.document. When a key is pressed, the event deterministically reaches my app first, and the app can then cancel the event to prevent it from bubbling up to the window. So here's my setup:

window.document.addEventListener(
  'keydown',
  (keyEvent) => {
    if(!spatialNavigation.paused){
      /* Allow react-spatial-navigation to be the only handler of this keyEvent.
       * The KeyEvent will bubble up to the window from here, where
       * react-spatial-navigation will handle it. */
      return;
    }
    // Take action based on the key event, then:
    keyEvent.preventDefault();
    keyEvent.stopPropagation();
    // Now the keyEvent won't propagate onward to react-spatial-navigation.
    spatialNavigation.resume();
  }
);
jbbpatel94 commented 4 years ago

@predikament any reason for keyEvent.stopPropagation(); preventing the event from propagation.

I want to know more about this one

predikament commented 4 years ago

Hello @jbbpatel94!

Bit confused if this question is to me, or if you meant to ask @shirakaba about his snippet above.

If the question is why it is used in this library, it's to avoid side-effects and unintended default key event handling, as the intention for this library is to handle navigation.

jbbpatel94 commented 4 years ago

it is preventing event from propagating to parent view.

predikament commented 4 years ago

it is preventing event from propagating to parent view.

This is correct, that is the intention.

I see you've also opened a PR (#74). I am going to close this question now since it's going a bit out of scope.