From 175a04739d7eafd03e1059a279bf93dd691a3714 Mon Sep 17 00:00:00 2001
From: shleewhite
Date: Tue, 30 Sep 2025 12:11:55 -0400
Subject: [PATCH 1/3] feat: improve lifecycle management by removing
ember-render-modifiers
---
.changeset/rich-zoos-type.md | 11 +++
.../src/components/hds/flyout/index.hbs | 3 +-
.../src/components/hds/flyout/index.ts | 83 ++++++++-----------
.../src/components/hds/modal/index.hbs | 3 +-
.../src/components/hds/modal/index.ts | 67 +++++++--------
.../app/templates/page-components/flyout.hbs | 18 ++--
.../app/templates/page-components/modal.hbs | 18 ++--
7 files changed, 97 insertions(+), 106 deletions(-)
create mode 100644 .changeset/rich-zoos-type.md
diff --git a/.changeset/rich-zoos-type.md b/.changeset/rich-zoos-type.md
new file mode 100644
index 00000000000..b0170b669ed
--- /dev/null
+++ b/.changeset/rich-zoos-type.md
@@ -0,0 +1,11 @@
+---
+"@hashicorp/design-system-components": patch
+---
+
+
+`Modal` - Refactored the component to not use `ember-render-modifiers` which fixes issues where the DOM may not be cleaned up when the Modal is closed.
+
+
+
+`Flyout` - Refactored the component to not use `ember-render-modifiers` which fixes issues where the DOM may not be cleaned up when the Flyout is closed.
+
\ No newline at end of file
diff --git a/packages/components/src/components/hds/flyout/index.hbs b/packages/components/src/components/hds/flyout/index.hbs
index 949ca208a42..8c15b2b1f35 100644
--- a/packages/components/src/components/hds/flyout/index.hbs
+++ b/packages/components/src/components/hds/flyout/index.hbs
@@ -6,8 +6,7 @@
class={{this.classNames}}
...attributes
aria-labelledby={{this.id}}
- {{did-insert this.didInsert}}
- {{will-destroy this.willDestroyNode}}
+ {{this._registerDialog}}
{{! @glint-expect-error - https://github.com/josemarluedke/ember-focus-trap/issues/86 }}
{{focus-trap isActive=this._isOpen focusTrapOptions=(hash onDeactivate=this.onDismiss clickOutsideDeactivates=true)}}
>
diff --git a/packages/components/src/components/hds/flyout/index.ts b/packages/components/src/components/hds/flyout/index.ts
index 4861fe385c6..772dc5da816 100644
--- a/packages/components/src/components/hds/flyout/index.ts
+++ b/packages/components/src/components/hds/flyout/index.ts
@@ -10,6 +10,7 @@ import { assert } from '@ember/debug';
import { getElementId } from '../../../utils/hds-get-element-id.ts';
import { buildWaiter } from '@ember/test-waiters';
import type { WithBoundArgs } from '@glint/template';
+import { modifier } from 'ember-modifier';
import type { HdsFlyoutSizes } from './types.ts';
@@ -65,14 +66,6 @@ export default class HdsFlyout extends Component {
private _body!: HTMLElement;
private _bodyInitialOverflowValue = '';
- /**
- * Sets the size of the flyout
- * Accepted values: medium, large
- *
- * @param size
- * @type {string}
- * @default 'medium'
- */
get size(): HdsFlyoutSizes {
const { size = DEFAULT_SIZE } = this.args;
@@ -86,18 +79,10 @@ export default class HdsFlyout extends Component {
return size;
}
- /**
- * Calculates the unique ID to assign to the title
- */
get id(): string {
return getElementId(this);
}
- /**
- * Get the class names to apply to the component.
- * @method classNames
- * @return {string} The "class" attribute to apply to the component.
- */
get classNames(): string {
const classes = ['hds-flyout'];
@@ -113,10 +98,32 @@ export default class HdsFlyout extends Component {
}
this._isOpen = false;
+
+ // Reset page `overflow` property
+ if (this._body) {
+ this._body.style.removeProperty('overflow');
+ if (this._bodyInitialOverflowValue === '') {
+ if (this._body.style.length === 0) {
+ this._body.removeAttribute('style');
+ }
+ } else {
+ this._body.style.setProperty(
+ 'overflow',
+ this._bodyInitialOverflowValue
+ );
+ }
+ }
+
+ // Return focus to a specific element (if provided)
+ if (this.args.returnFocusTo) {
+ const initiator = document.getElementById(this.args.returnFocusTo);
+ if (initiator) {
+ initiator.focus();
+ }
+ }
}
- @action
- didInsert(element: HTMLDialogElement): void {
+ private _registerDialog = modifier((element: HTMLDialogElement) => {
// Store references of `
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
+ key, click outside, 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.
+ HTML element.
@@ -363,9 +361,9 @@
flyout 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.
+ key, click outside, click dismiss button) because it will trigger directly the
+ _registerDialog
+ modifier's cleanup function.
This is not equivalent
to a manual dismiss (Esc
- key, click outsite, click dismiss button) because it will trigger directly the
- willDestroyNode
- action.
+ key, click outside, click dismiss button) because it will directly trigger the
+ _registerDialog
+ modifier's cleanup function.