GavinJoyce / ember-headlessui

https://gavinjoyce.github.io/ember-headlessui/
Other
92 stars 34 forks source link

BUG: click outside <Dialog /> should be allowed #170

Open rreckonerr opened 2 years ago

rreckonerr commented 2 years ago

Usecase

I'm working on adding notifications to the app, and it should be possible to click/close the notification without closing the current <Dialog />

Problem

At the moment any click outside <Dialog /> will trigger @onClose. The only exception is child dialogs spawned by the modal (handled by dialog-stack-provider service).

This behavior used to be the same in @headlessui/react@v1.5.0, but since @headlessui/react@v1.6.0 it's possible to click outside the dialog without triggering the @onClose action IF the "outsider" is wrapped with headlessui <Portal /> component.

Workaround

As a workaround, I extended the dialog.js component as follows

import { action } from '@ember/object';
import EmberHeadlessUiDialog from 'ember-headlessui/components/dialog.js';

export default class extends EmberHeadlessUiDialog {
  @action
  allowOutsideClick(e) {
    const target = e.target;

    if (target && target.tagName !== 'BODY') {
      this.outsideClickedElement = target;
    }

    // 👇
    // this.onClose();

    return true;
  }
}

Resources

far-fetched commented 1 year ago

Hello @rreckonerr :wave:

So you expect that clicking on blue box it will keep modal opened ? E.g. in a scenario when we use external lib which appends toast as last body element

https://user-images.githubusercontent.com/11621383/208064012-418b805e-f264-45b1-a454-27274ea516f3.mp4

far-fetched commented 1 year ago

I found a relevant test which you described:

...without triggering the @onclose action IF the "outsider" is wrapped with headlessui component.

https://github.com/tailwindlabs/headlessui/blob/main/packages/%40headlessui-react/src/components/dialog/dialog.test.tsx#L1097

Looking at what others folks in topic said, I am not sure that this would be a solution for you issue :thinking: Imagine that you cannot wrap Toast component in .hbs template and someone just calls toast in .js class e.g.

...
this.toastService.success('message...');
...

And magic goes inside service provided by 3th lib. Then still it will close dialog when clicking on toast box :thinking:

Your workaround will fail with this test: https://github.com/GavinJoyce/ember-headlessui/blob/master/test-app/tests/integration/components/dialog-test.js#L478

as we control visibility of modal by passing isOpen and onClose cb, what about passing onClose more adjusted to your needs:

onClose(event) {
   if (event.doesNotComeFromYourToastBox) {
      this.isModalOpen = false;
   }
}

Any chance does it work ?

rreckonerr commented 1 year ago

Hi, @far-fetched! Thanks for your investigation, it totally makes sense. Yeah, passing the click event to onClose should work just fine!

roomman commented 1 year ago

I also have a use case that requires the "click outside" to be disabled for specific events. The event isn't currently being passed to the onClose action. @far-fetched would you accept a PR to add the event as an overload?

far-fetched commented 1 year ago

According to the Official API it does not pass event in callback either.

Can you show your example (might be simplified) in some sandbox code ? Maybe we can resolve it differently.

roomman commented 1 year ago

Can you show your example

Yes, I'll put something together, thanks. I'm away for a few days now.

It's a very basic implementation that renders a form. One of the form inputs is a select that renders its options into a portal. When you select an option it closes the modal prematurely. The only way I can see to prevent this is to check the event - as you suggested above - but I don't have access to it.