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

Option to opt-out from Focus Trap #435

Closed
zeppelin opened this issue Sep 3, 2021 · 5 comments · Fixed by #517
Closed

Option to opt-out from Focus Trap #435

zeppelin opened this issue Sep 3, 2021 · 5 comments · Fixed by #517
Labels
enhancement New feature or request

Comments

@zeppelin
Copy link
Member

zeppelin commented Sep 3, 2021

Some addons like Ember Power Select render outside the component they're invoked in, making it impossible to use with EPM. (Although EPS can be forced to render in place, but could be difficult to deal with for various reasons). I saw no option in Focus Trap to exclude certain selectors.

I know it would reduce accesibility, but spending time with code that handle modals if we don't have EPM also takes away precious time we could otherwise spend with making our app more accessible.

It doesn't even have to be public API, just an option that's one would only use if really needed it.

Should I open a PR?

@kevinansfield
Copy link

kevinansfield commented Sep 8, 2021

Added a comment to this old issue that is along the same lines #295 (comment)

It is possible to prevent clicks on ember-basic-dropdown components closing the modals by overriding the modals service in your app, eg:

import EPMModalsService from 'ember-promise-modals/services/modals';

export default class ModalsService extends EPMModalsService {
    clickOutsideDeactivates(event) {
        let shouldClose = true;

        for (const elem of event.path) {
            if (elem.classList?.contains('ember-basic-dropdown-content')) {
                shouldClose = false;
                break;
            }
        }

        return shouldClose;
    }
}

However, because there's no equivalent option passthrough for allowOutsideClick the clicks get prevented from doing anything at all.

@kevinansfield
Copy link

kevinansfield commented Sep 8, 2021

As a proof-of-concept I modified the modal.js file in ember-promise-modals locally so that an allowOutsideClick option is passed through:

didInsertElement() {
    this._super(...arguments);

    let { allowOutsideClick, clickOutsideDeactivates } = this.modals;
    let element = document.getElementById(this.modalElementId);
    let options = {
      allowOutsideClick,
      clickOutsideDeactivates,
      ...

Then in my app's modals service, added the option as a function:

allowOutsideClick(event) {
    let shouldAllow = false;

    for (const elem of event.path) {
        if (elem.classList?.contains('ember-basic-dropdown-content')) {
            shouldAllow = true;
            break;
        }
    }

    return shouldAllow;
}

With that everything works well with dropdowns inside of a modal. I guess the question is whether allowOutsideClick is a valid option to add to the addon service or if there should be some other route to configuring or disabling focus-trap. The previous argument against adding the option was that the addon becomes tied to focus-trap's API but I'd argue the addon is already tied heavily to focus-trap's behaviour so it's not exactly an implementation detail right now.

kevinansfield added a commit to TryGhost/ember-promise-modals that referenced this issue Sep 13, 2021
refs mainmatter#435
refs mainmatter#295

https://github.com/focus-trap/focus-trap is used internally for keeping focus inside a modal and for clicks outside to close the modal. It's `clickOutsideDecactivates` config is exposed allowing for  clicks on wormholed elements such as dropdowns inside a modal to not close the modal unexpectedly, however without the companion `allowOutsideClick` config those clicks are prevented from performing any interaction.

- added `allowOutsideClick` to the options passed through from the `modals` service to the `focus-trap` initialisation
kevinansfield added a commit to TryGhost/ember-promise-modals that referenced this issue Sep 13, 2021
refs mainmatter#435
refs mainmatter#295

https://github.com/focus-trap/focus-trap is used internally for keeping focus inside a modal and for clicks outside to close the modal. It's `clickOutsideDecactivates` config is exposed allowing for  clicks on wormholed elements such as dropdowns inside a modal to not close the modal unexpectedly, however without the companion `allowOutsideClick` config those clicks are prevented from performing any interaction.

- added `allowOutsideClick` to the options passed through from the `modals` service to the `focus-trap` initialisation
kevinansfield added a commit to TryGhost/ember-promise-modals that referenced this issue Sep 16, 2021
refs mainmatter#435
refs mainmatter#295

https://github.com/focus-trap/focus-trap is used internally for keeping focus inside a modal and for handling modal closing on certain events. If the consuming app wants to manage deactivation/close-inducing events itself then it needs some way to pass `focus-trap` config through to turn off that functionality.

- added `escapeDeactivates` to the options passed through from the `modals` service to the `focus-trap` initialisation
@pichfl
Copy link
Contributor

pichfl commented Nov 5, 2021

@zeppelin @kevinansfield I wouldn't mind having that option at all, a PR for this (including some form of documentation in the README) would be much appreciated.

@pichfl pichfl added the enhancement New feature or request label Nov 5, 2021
@zeppelin
Copy link
Member Author

zeppelin commented Nov 5, 2021

@pichfl @kevinansfield We currently patch EPM in our project:

diff --git a/node_modules/ember-promise-modals/addon/components/modal.js b/node_modules/ember-promise-modals/addon/components/modal.js
index f145b4f..331ed18 100644
--- a/node_modules/ember-promise-modals/addon/components/modal.js
+++ b/node_modules/ember-promise-modals/addon/components/modal.js
@@ -30,7 +30,7 @@ export default Component.extend({
   didInsertElement() {
     this._super(...arguments);
 
-    let { clickOutsideDeactivates } = this.modals;
+    let { clickOutsideDeactivates, _disableFocusTrap } = this.modals;
     let element = document.getElementById(this.modalElementId);
     let options = {
       clickOutsideDeactivates,
@@ -44,8 +44,10 @@ export default Component.extend({
       },
     };
 
-    this.focusTrap = createFocusTrap(element, options);
-    this.focusTrap.activate();
+    if (!_disableFocusTrap) {
+      this.focusTrap = createFocusTrap(element, options);
+      this.focusTrap.activate();
+    }

So right now this pretty much looks like a private/undocumented option. Are you cool with it, or just make it public (and optionally reverse the wording to enableFocusTrap with default true)?

I can update the README for any of the solutions above.

@pichfl
Copy link
Contributor

pichfl commented Nov 5, 2021

I would prefer it being public and documented API, I feel like more people might run into this issue. I would also keep disableFocusTrap as the name 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants