wailsapp / wails

Create beautiful applications using Go
https://wails.io
MIT License
25.3k stars 1.21k forks source link

[OSX] Allow to set tabFocusesLinks #2919

Closed fkhadra closed 1 year ago

fkhadra commented 1 year ago

Is your feature request related to a problem? Please describe.

"By default, Apple computers have an operating system (OS) level setting that limits the Tab key to "Text boxes and lists only". This can be confusing, if not frustrating, for those unaware of this setting and expect keyboard focus to be similar to navigating on a Windows machine." For example, links are not focusable by default when using the keyboard. See https://www.a11yproject.com/posts/macos-browser-keyboard-navigation/ for full details.

Describe the solution you'd like

Webkit exposes a setting to make links focusable using the keyboard under WKPrefences.tabFocusesLinks. This is documented here.

I see 2 possible solutions:

Locally, I've tried the first solution given it was the fastest to test and it works. I've added the line below.

// file: wails/v2/internal/frontend/desktop/darwin/WailsContext.m
// around line 219, after WKWebViewConfiguration instantiation 
config.preferences.tabFocusesLinks = true;

I would be happy to contribute if needed.

Describe alternatives you've considered

Currently, I'm handling the tab navigation with javascript. I create a tree walker with all focusable element and use it to navigate across focusable nodes.

const treeWalker = document.createTreeWalker(
    document.body,
    NodeFilter.SHOW_ELEMENT,
    {
      acceptNode: (node) =>
        (node as HTMLElement).tabIndex >= 0
          ? NodeFilter.FILTER_ACCEPT
          : NodeFilter.FILTER_SKIP,
    },
  );

  function handleTab(e: KeyboardEvent) {
    const focusNext = e.key === "Tab" && !e.shiftKey;
    const focusPrevious = e.key === "Tab" && e.shiftKey;

    if (focusNext || focusPrevious) {
      e.preventDefault();
      treeWalker.currentNode = document.activeElement as Node;

      let next = focusNext ? treeWalker.nextNode() : treeWalker.previousNode();

      if (next === null) {
        treeWalker.currentNode = treeWalker.root;
        next = focusNext ? treeWalker.nextNode() : treeWalker.lastChild();
      }

      (next as HTMLElement).focus();
    }
  }

  document.addEventListener("keydown", handleTab);

Additional context

No response

leaanthony commented 1 year ago

Thanks for opening this! I think we can add a new Preferences key under the Mac settings for these kinds of options and plumb them into the WebKit preferences.

We'll need to add a tristate Boolean for this kind of thing to detect the difference between "unset" and false.

fkhadra commented 1 year ago

Thank you. I'll prepare a PR for that 👍🏽

leaanthony commented 1 year ago

Awesome! I created https://GitHub.com/leaanthony/u for tristate scalars. Using u.Bool will mean we can tell whether to just leave the default value or not.

fkhadra commented 1 year ago

Hey @leaanthony, when I try to install u I'm getting the following error

go: github.com/leaanthony/u@v1.0.0: parsing go.mod:
    module declares its path as: u
            but was required as: github.com/leaanthony/u

I believe the go.mod needs to be updated as follow, can you confirm? If so I can prepare a PR

- module u
+ module github.com/leaanthony/u

thanks!

leaanthony commented 1 year ago

🤦 yes I need to fix that. Thanks for letting me know.

leaanthony commented 1 year ago

Fixed 👍

fkhadra commented 1 year ago

Awesome, thanks for the fix I'll give it a try later.

fkhadra commented 1 year ago

Regarding the scope, I thought about exposing the following preferences to begin with. The list can be extended later if needed.

When it comes to the implementation

// setting preferences for a wails app

preferences := Preferences{
    TabFocusesLinks: u.NewBool(true),
}
// vs
prefrences := Preferences{
    TabFocusesLinks: true,
}

Thanks in advance!

leaanthony commented 1 year ago

Yes, expose the tri-state vars in the options. For objective C I'd use a struct of C bool pointers to manage that with null checks in the preferences set up.

fkhadra commented 1 year ago

Thanks a lot!