diff --git a/.changeset/ninety-maps-bow.md b/.changeset/ninety-maps-bow.md new file mode 100644 index 00000000000..1bffe95472e --- /dev/null +++ b/.changeset/ninety-maps-bow.md @@ -0,0 +1,5 @@ +--- +"@hashicorp/design-system-components": patch +--- + +`Modal` - Fixed destructor when the component is removed while open diff --git a/packages/components/src/components/hds/modal/index.hbs b/packages/components/src/components/hds/modal/index.hbs index 7ddc96915d0..3ba95484712 100644 --- a/packages/components/src/components/hds/modal/index.hbs +++ b/packages/components/src/components/hds/modal/index.hbs @@ -7,7 +7,6 @@ ...attributes aria-labelledby={{this.id}} {{did-insert this.didInsert}} - {{will-destroy this.willDestroyNode}} {{! @glint-expect-error - https://github.com/josemarluedke/ember-focus-trap/issues/86 }} {{focus-trap isActive=this._isOpen focusTrapOptions=(hash onDeactivate=this.onDismiss)}} > diff --git a/packages/components/src/components/hds/modal/index.ts b/packages/components/src/components/hds/modal/index.ts index 9a2c8acb194..9efbfa884ab 100644 --- a/packages/components/src/components/hds/modal/index.ts +++ b/packages/components/src/components/hds/modal/index.ts @@ -69,6 +69,18 @@ export default class HdsModal extends Component { super(owner, args); registerDestructor(this, (): void => { + // if the is removed from the dom while open we emulate the close event + if (this._element && this._isOpen) { + this._element.dispatchEvent(new Event('close')); + + this._element.removeEventListener( + 'close', + // eslint-disable-next-line @typescript-eslint/unbound-method + this.registerOnCloseCallback, + true + ); + } + document.removeEventListener('click', this._clickHandler, true); }); } @@ -201,18 +213,6 @@ export default class HdsModal extends Component { }); } - @action - willDestroyNode(): void { - if (this._element) { - this._element.removeEventListener( - 'close', - // eslint-disable-next-line @typescript-eslint/unbound-method - this.registerOnCloseCallback, - true - ); - } - } - @action open(): void { // Make modal dialog visible using the native `showModal` method diff --git a/showcase/app/controllers/components/modal.js b/showcase/app/controllers/components/modal.js index 7fd256e21b9..4dfa332876b 100644 --- a/showcase/app/controllers/components/modal.js +++ b/showcase/app/controllers/components/modal.js @@ -10,6 +10,8 @@ import { tracked } from '@glimmer/tracking'; export default class ModalController extends Controller { @tracked basicModalActive = false; @tracked longModalActive = false; + @tracked deactivateModalOnCloseActive = false; + @tracked deactivateModalOnDestroyActive = false; @tracked formModalActive = false; @tracked tabsModalActive = false; @tracked dropdownModalActive = false; diff --git a/showcase/app/templates/components/modal.hbs b/showcase/app/templates/components/modal.hbs index 355153aadc2..ce396279591 100644 --- a/showcase/app/templates/components/modal.hbs +++ b/showcase/app/templates/components/modal.hbs @@ -276,6 +276,68 @@ {{/if}} + + + {{#if this.deactivateModalOnCloseActive}} + + + Modal title + + +

Clicking the "confirm" button executes the + F.close + method.

+

This is equivalent to a + manual dismiss (Esc + key, click outsite, click dismiss button) because they're all calling the same function, which invokes the + native + close() + method of the + Dialog + HTML element, who then will cause the + willDestroyNode + action to execute.

+
+ + + +
+ {{/if}} + + + + {{#if this.deactivateModalOnDestroyActive}} + + + Modal title + + +

Clicking the "confirm" button will remove the modal + from the DOM.

+

This is not equivalent to + a manual dismiss (Esc + key, click outsite, click dismiss button) because it will trigger directly the + willDestroyNode + action.

+
+ + + +
+ {{/if}} +

diff --git a/showcase/tests/integration/components/hds/modal/index-test.js b/showcase/tests/integration/components/hds/modal/index-test.js index 91d5886a49b..b65dec5f9c8 100644 --- a/showcase/tests/integration/components/hds/modal/index-test.js +++ b/showcase/tests/integration/components/hds/modal/index-test.js @@ -301,6 +301,26 @@ module('Integration | Component | hds/modal/index', function (hooks) { assert.ok(closed); }); + test('it should call `onClose` function if the component is destroyed while the modal is open', async function (assert) { + let closed = false; + this.set('onClose', () => (closed = true)); + + this.set('showModal', true); + + await render( + hbs` + {{#if this.showModal}} + + Title + + {{/if}} + `, + ); + + this.set('showModal', false); + assert.ok(closed); + }); + // ASSERTIONS test('it should throw an assertion if an incorrect value for @size is provided', async function (assert) {