Monorepo for Tangled tangled.org

proposal: add shortcut to submit issues, comments, and PRs #412

open opened by marco.tngl.sh edited

This generalizes #397 to cover comments and PRs as well and provides the foundation to add other shortcuts in the future.

Shortcut#

For Linux/Windows: ctrl+enter
For macOS: cmd+enter

Proposed Behavior#

When creating/editing an issue/PR the shortcut can be used to submit the form, regardless of which of the inputs (title, body, etc.) is focused.

The same applies for comments—when the textarea of a comment is focused, it is submitted.

For the shortcut, the same rules as for the submit button apply—i.e. one cannot submit a comment through the shortcut if the textarea is empty.

Proposed Implementation#

A module shortcuts.js, which exports registerShortcuts and a focus helper.
registerShortcuts registers the provided shortcuts and returns a shared EventTarget for attaching listeners.

Registering Shortcuts#

Shortcuts would be registered like this:

import {registerShortcuts} from '/static/shortcuts.js';

registerShortcuts(['$mod+Enter']).addEventListener('$mod+Enter', handler);

With multiple shortcuts like this:

import {registerShortcuts} from '/static/shortcuts.js';

const shortcuts = registerShortcuts(['$mod+Enter', 'Escape']);
shortcuts.addEventListener('$mod+Enter', handleSubmit);
shortcuts.addEventListener('Escape', handleCancel);

Internally, the shortcuts are deduplicated, so there is only ever one listener on window.

Focus helpers#

Since we'll often need to check what is currently focused to decide if the handler should run, we can also export a helper which checks if the activeElement (i.e. focused element) matches a selector.

Together it could look like this:

import {registerShortcuts, isFocused} from '/static/shortcuts.js';

registerShortcuts(['$mod+Enter']).addEventListener('$mod+Enter', () => {
    if(isFocused('#issue-form #title, #issue-form #body')) {
        // submit form
    }
});

Alternative approaches considered#

I also explored scoped element-level shortcuts, where a data-shortcuts='["$mod+Enter"]' attribute could be defined on the form element.

In this approach the events were dispatched directly on the closest [data-shortcuts] ancestor of the focused element. This was intended to simplify event handlers, but ultimately didn't provide much benefit.
The element boundary of a whole form was too coarse—buttons inside the form would also match, so it was still necessary to check focus explicitly, making the boilerplate roughly the same as the proposed approach.

Dependencies#

Here we can either use a library like tinykeys or a custom implementation.
Since tinykeys is just ~650 B, I feel like it is small enough, and it handles cross-platform modifier keys and edge cases that are easy to get wrong in a custom implementation.

Also, this will enable us to add other shortcuts easily in the future.

Happy to hear your thoughts and feedback!

for most forms, we can just slap on this attribute:

hx-trigger="click, keyup[ctrlKey && key=='Enter'] from:body"

and it will trigger the submit action.

since this is just an alternate trigger mechanism, this would automagically handle the existing form validations etc. the only thing we have to be mindful of is to insert this correctly in every form where it makes sense.

Ah sorry for missing this…

I played around with this and it seems to work quite well for the basic case.

Some thoughts/things I noticed:

  1. I think we should still allow cmd+Enter on macOS, which we could do with keydown[(ctrlKey || metaKey) && key=='Enter'] (note: keyup doesn't work reliably for modifier combos on macOS).
    The downside of this approach is, that it would allow both (ctrl and cmd) everywhere.

  2. from:body has the problem that it is too coarse and would also trigger on the buttons and this wouldn't play nice with multiple components on the same page having shortcuts. We can solve this with, for example from:(#title,#body).

  3. You mentioned this would also handle the existing form validations, but I couldn't get that working. I tried it on the #comment-button in newComment.html and I could use the shortcut even though the button was disabled. Maybe you have an idea what I was missing?
    If it doesn't work automagically we could provide a function as an event filter.

thanks for digging around! agreed on 1 & 2. a for 3: the newComment form is a bit special, it uses js to disable/change the button text based on whether the textarea has content.

re: 3; Yeah I saw that. We can can add a function which checks if the button is disabled as an event filter for these scenarios.

I'll start working on a PR :)

sign up or login to add to the discussion
Labels

None yet.

area

None yet.

assignee

None yet.

Participants 2
AT URI
at://did:plc:uvlgxr6xf446eugiky6s3swz/sh.tangled.repo.issue/3metf7hrr2p22