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

Capture global keypress event to dismiss modal #288

Open
mwx23 opened this issue Nov 8, 2022 · 5 comments
Open

Capture global keypress event to dismiss modal #288

mwx23 opened this issue Nov 8, 2022 · 5 comments
Labels
enhancement New feature or request help wanted Extra attention is needed question Further information is requested

Comments

@mwx23
Copy link

mwx23 commented Nov 8, 2022

Lately I've been using tailwindcss and daisyui for my UI css. There's some nice css behaviours those libs have to handle visibility etc that seems to get swallowed by lona. This issue isn't about that (I'll post a minimal example later), as a work-around I'd just like to capture key events. Specifically if a modal is displayed and esc is pressed, toggle close the modal.

My general question is it possible to capture a keypress event and have it sent to the backend?

I've tried handle_input_event_root on a LonaView and handle_input_event on a Widget but that doesn't seem to work unless a TextInput is involved and focused.

I can write a frontend widget to do this (I think) but is there a more lona way to achieve this?

If I were to generalise the issue even more, is there a way to subscribe to frontend DOM events from the backend? This might be out of scope, but I saw in other issues you talking about v2 so I'm hopeful :)

@fscherf
Copy link
Member

fscherf commented Nov 9, 2022

Hi @mwx23,

Lately I've been using tailwindcss and daisyui for my UI css

Nice! I didn't know daisyui, but it looks pretty cool and versatile. If we can resolve your issues we could make package for lona like https://github.com/lona-web-org/lona-bootstrap-5

I've tried handle_input_event_root on a LonaView and handle_input_event on a Widget but that doesn't seem to work unless a TextInput is involved and focused.

If I were to generalise the issue even more, is there a way to subscribe to frontend DOM events from the backend?

Actually, that is exactly how events are implemented. Every node has a list of events it can fire (Node.events). This list is empty by default, but some nodes from the standard library like lona.html.Button come pre-configured with for click events. You can add any event type from lona.html to any node (currently implemented: CLICK, FOCUS, CHANGE, BLUR).

from lona.html import CLICK, FOCUS, CHANGE, BLUR
from lona.html import Div

my_div = Div(events=[CLICK])

The information that my_div can be clicked gets send to JavaScript client with the actual HTML. When the client renders
my_div a JavaScript event handler gets setup that produces a high-level event that can be send back over the websocket, so
Lona can call my_div.handle_click().

That means: With this approach, you can only handle events that are supported by both the server and the client, and are configured correctly.

My general question is it possible to capture a keypress event and have it sent to the backend?
[...]
I can write a frontend widget to do this (I think) but is there a more lona way to achieve this?

Currently, that is the way to go. Lona frontend widgets can send custom events. That means you can create a Modal widget, with a specialized frontend widget that captures global keypresses and sends event to the server to close the modal. That's what i currently do in bootstrap code aswell.

There are ideas to extend the event API to make code like this work:

from lona.html import KEY_ALT, KEY_T
from lona.html import Div

my_div = Div(events=[KEY_ALT + KEY_T)  # simple key binding

but the problem with first implementation was that most elements have to set tabindex to be able to emit key events, and then the key events only work when the right container is focused. The next idea was to let the view describe the key bindings globally like this:

from lona.html import KEY_ALT, KEY_T
from lona import LonaView

class MyLonaView(LonaView):
    KEY_BINDINGS = {
        KEY_ALT + KEY_T: self.handle_alt_t,
    }

but until now the need was not big enough to implement something like this. Also i don't have a good idea yet how to connect global key event (like in implementation 2) to a very specific node like a daisyui modal.

@fscherf fscherf added help wanted Extra attention is needed question Further information is requested labels Nov 9, 2022
@fscherf
Copy link
Member

fscherf commented Dec 2, 2022

Hi @mwx23,

I did some prototyping came up with this API:

from lona.html import HTML, Div, H1, KeyboardShortcuts
from lona import LonaView

from my_code import Modal


class MyLonaView(LonaView):
    def handle_alt_enter(self, input_event):
        print('ALT + Enter was pressed')

    def handle_arrow_up(self, input_event):
        print('Arrow Up was pressed')

    def dismiss_modal(self, input_event):
        with self.html.lock:
            if self.modal.visible:
                self.modal.dismiss()

    def handle_request(self, request):
        self.shortcuts = KeyboardShortcuts({
            'ALT+ENTER': self.handle_alt_enter,
            'ARROW-UP': self.handle_arrow_up,
            'ESC': self.dismiss_modal,
        })

        self.modal = Modal()

        return HTML(
            H1('Hello World'),
            self.modal,
            self.shortcuts,
        )

The idea is to add a new component that serves a JavaScript widget that interprets the config given to the KeyboardShortcuts class (the name is not final), and sends custom input events which get mapped to the configured callbacks on the server.

@SmithChart, @maratori, @grigolet, @laundmo

@fscherf fscherf added the enhancement New feature or request label Dec 2, 2022
@maratori
Copy link
Member

maratori commented Dec 3, 2022

Looks nice 👍

@SmithChart
Copy link
Contributor

I really like the idea of handlers for global shortcuts in the frontend.

How would this integrate with a higher-level integration like lona-somethingcss that would probably like to handle some key presses and a view that would like to handle some others?

@fscherf
Copy link
Member

fscherf commented May 31, 2023

@SmithChart: That's a good question, and I am not sure yet. Currently, Lona implements event capturing (handling events from the outer-most node first) only very basic, and I plan on changing this. Every node should have a capture_input_event(). With that feature in place, use-cases like this should be feasible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help wanted Extra attention is needed question Further information is requested
Projects
None yet
Development

No branches or pull requests

4 participants