@momentum-design/components 0.75.2 → 0.75.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,6 +8,10 @@ declare const Dialog_base: import("../../utils/mixins/index.types").Constructor<
8
8
  * The dialog is available in three sizes: small, medium, and large. It may also receive custom styling/sizing.
9
9
  * The dialog interrupts the user and will block interaction with the rest of the application until it is closed.
10
10
  *
11
+ * The dialog can be controlled solely through the `visible` property, no trigger element is required.
12
+ * If a `triggerId` is provided, the dialog will manage focus with that element, otherwise it will
13
+ * remember the previously focused element before the dialog was opened.
14
+ *
11
15
  * Dialog component have 2 variants: default and promotional.
12
16
  *
13
17
  * **Accessibility notes for consuming (have to be explicitly set when you consume the component)**
@@ -36,6 +40,7 @@ declare const Dialog_base: import("../../utils/mixins/index.types").Constructor<
36
40
  * @cssproperty --mdc-dialog-elevation-3 - elevation of the dialog
37
41
  * @cssproperty --mdc-dialog-width - width of the dialog
38
42
  *
43
+ * @slot header-prefix - Slot for the dialog header content. This can be used to pass custom header content.
39
44
  * @slot dialog-body - Slot for the dialog body content
40
45
  * @slot footer-link - This slot is for passing `mdc-link` component within the footer section.
41
46
  * @slot footer-button-secondary - This slot is for passing secondary variant of `mdc-button` component
@@ -109,6 +114,8 @@ declare class Dialog extends Dialog_base {
109
114
  private utils;
110
115
  /** @internal */
111
116
  backdropElement: HTMLElement | null;
117
+ /** @internal */
118
+ private lastActiveElement;
112
119
  constructor();
113
120
  protected firstUpdated(changedProperties: PropertyValues): Promise<void>;
114
121
  disconnectedCallback(): Promise<void>;
@@ -140,6 +147,11 @@ declare class Dialog extends Dialog_base {
140
147
  * @internal
141
148
  */
142
149
  hideDialog: () => void;
150
+ /**
151
+ * Shows the dialog.
152
+ * @internal
153
+ */
154
+ showDialog: () => void;
143
155
  /**
144
156
  * Sets the focusable elements inside the dialog.
145
157
  */
@@ -25,6 +25,10 @@ import { CardAndDialogFooterMixin } from '../../utils/mixins/CardAndDialogFooter
25
25
  * The dialog is available in three sizes: small, medium, and large. It may also receive custom styling/sizing.
26
26
  * The dialog interrupts the user and will block interaction with the rest of the application until it is closed.
27
27
  *
28
+ * The dialog can be controlled solely through the `visible` property, no trigger element is required.
29
+ * If a `triggerId` is provided, the dialog will manage focus with that element, otherwise it will
30
+ * remember the previously focused element before the dialog was opened.
31
+ *
28
32
  * Dialog component have 2 variants: default and promotional.
29
33
  *
30
34
  * **Accessibility notes for consuming (have to be explicitly set when you consume the component)**
@@ -53,6 +57,7 @@ import { CardAndDialogFooterMixin } from '../../utils/mixins/CardAndDialogFooter
53
57
  * @cssproperty --mdc-dialog-elevation-3 - elevation of the dialog
54
58
  * @cssproperty --mdc-dialog-width - width of the dialog
55
59
  *
60
+ * @slot header-prefix - Slot for the dialog header content. This can be used to pass custom header content.
56
61
  * @slot dialog-body - Slot for the dialog body content
57
62
  * @slot footer-link - This slot is for passing `mdc-link` component within the footer section.
58
63
  * @slot footer-button-secondary - This slot is for passing secondary variant of `mdc-button` component
@@ -126,6 +131,8 @@ class Dialog extends FocusTrapMixin(CardAndDialogFooterMixin(Component)) {
126
131
  this.triggerElement = null;
127
132
  /** @internal */
128
133
  this.backdropElement = null;
134
+ /** @internal */
135
+ this.lastActiveElement = null;
129
136
  /**
130
137
  * Handles the escape keydown event to close the dialog.
131
138
  * @internal
@@ -145,6 +152,13 @@ class Dialog extends FocusTrapMixin(CardAndDialogFooterMixin(Component)) {
145
152
  this.hideDialog = () => {
146
153
  this.visible = false;
147
154
  };
155
+ /**
156
+ * Shows the dialog.
157
+ * @internal
158
+ */
159
+ this.showDialog = () => {
160
+ this.visible = true;
161
+ };
148
162
  /** @internal */
149
163
  this.utils = new DialogUtils(this);
150
164
  document.addEventListener('keydown', this.onEscapeKeydown);
@@ -169,8 +183,10 @@ class Dialog extends FocusTrapMixin(CardAndDialogFooterMixin(Component)) {
169
183
  * Sets up the trigger listener for focus trap
170
184
  */
171
185
  setupTriggerListener() {
172
- if (!this.triggerId)
186
+ if (!this.triggerId) {
187
+ this.addEventListener('focus-trap-exit', this.hideDialog);
173
188
  return;
189
+ }
174
190
  this.triggerElement = this.getRootNode().querySelector(`[id="${this.triggerId}"]`);
175
191
  if (!this.triggerElement)
176
192
  return;
@@ -180,8 +196,6 @@ class Dialog extends FocusTrapMixin(CardAndDialogFooterMixin(Component)) {
180
196
  * Removes the trigger event listener
181
197
  */
182
198
  removeEventListeners() {
183
- if (!this.triggerElement)
184
- return;
185
199
  this.removeEventListener('focus-trap-exit', this.hideDialog);
186
200
  }
187
201
  async updated(changedProperties) {
@@ -209,26 +223,38 @@ class Dialog extends FocusTrapMixin(CardAndDialogFooterMixin(Component)) {
209
223
  * @param newValue - The new value of the visible property.
210
224
  */
211
225
  async isOpenUpdated(oldValue, newValue) {
212
- var _a, _b, _c;
213
- if (oldValue === newValue || !this.triggerElement) {
226
+ var _a, _b;
227
+ if (oldValue === newValue) {
214
228
  return;
215
229
  }
216
- if (newValue) {
230
+ if (newValue && !oldValue) {
231
+ // Store the currently focused element before opening the dialog
232
+ this.lastActiveElement = document.activeElement;
217
233
  this.enabledFocusTrap = true;
218
234
  this.enabledPreventScroll = true;
219
235
  this.utils.createBackdrop();
220
236
  await this.handleCreateDialogFirstUpdate();
221
- this.triggerElement.setAttribute('aria-expanded', 'true');
222
- this.triggerElement.setAttribute('aria-haspopup', this.triggerElement.getAttribute('aria-haspopup') || 'dialog');
237
+ // If we have a trigger element, update its attributes
238
+ if (this.triggerElement) {
239
+ this.triggerElement.setAttribute('aria-expanded', 'true');
240
+ this.triggerElement.setAttribute('aria-haspopup', this.triggerElement.getAttribute('aria-haspopup') || 'dialog');
241
+ }
223
242
  DialogEventManager.onShowDialog(this);
224
243
  }
225
- else {
244
+ else if (!newValue && oldValue) {
226
245
  (_a = this.backdropElement) === null || _a === void 0 ? void 0 : _a.remove();
227
246
  this.backdropElement = null;
228
247
  (_b = this.deactivateFocusTrap) === null || _b === void 0 ? void 0 : _b.call(this);
229
- this.triggerElement.removeAttribute('aria-expanded');
230
- this.triggerElement.removeAttribute('aria-haspopup');
231
- (_c = this.triggerElement) === null || _c === void 0 ? void 0 : _c.focus();
248
+ // If we have a trigger element, restore focus to it
249
+ if (this.triggerElement) {
250
+ this.triggerElement.removeAttribute('aria-expanded');
251
+ this.triggerElement.removeAttribute('aria-haspopup');
252
+ this.triggerElement.focus();
253
+ }
254
+ else if (this.lastActiveElement && this.lastActiveElement.focus) {
255
+ // Otherwise restore focus to the last active element
256
+ this.lastActiveElement.focus();
257
+ }
232
258
  DialogEventManager.onHideDialog(this);
233
259
  }
234
260
  }
@@ -248,14 +274,17 @@ class Dialog extends FocusTrapMixin(CardAndDialogFooterMixin(Component)) {
248
274
  return html `
249
275
  ${this.headerText
250
276
  ? html `
251
- <div part="header">
252
- <mdc-text
253
- part="header-text"
254
- tagname="${VALID_TEXT_TAGS[this.headerTagName.toUpperCase()]}"
255
- type="${TYPE.BODY_LARGE_BOLD}"
256
- >
257
- ${this.headerText}
258
- </mdc-text>
277
+ <div part="header-section">
278
+ <div part="header">
279
+ <slot name="header-prefix"></slot>
280
+ <mdc-text
281
+ part="header-text"
282
+ tagname="${VALID_TEXT_TAGS[this.headerTagName.toUpperCase()]}"
283
+ type="${TYPE.BODY_LARGE_BOLD}"
284
+ >
285
+ ${this.headerText}
286
+ </mdc-text>
287
+ </div>
259
288
  <mdc-text
260
289
  part="description-text"
261
290
  tagname="${VALID_TEXT_TAGS[this.descriptionTagName.toUpperCase()]}"
@@ -47,19 +47,25 @@ const styles = css `
47
47
  max-width: 100%;
48
48
  }
49
49
 
50
- :host::part(header),
50
+ :host::part(header-section),
51
51
  :host::part(body),
52
52
  :host::part(footer) {
53
53
  display: flex;
54
54
  align-self: stretch;
55
55
  }
56
56
 
57
- :host::part(header) {
57
+ :host::part(header-section) {
58
58
  flex-direction: column;
59
59
  align-items: flex-start;
60
60
  gap: 0.5rem;
61
61
  }
62
62
 
63
+ :host::part(header) {
64
+ display: flex;
65
+ align-items: center;
66
+ gap: 0.25rem;
67
+ }
68
+
63
69
  :host::part(header-text) {
64
70
  width: 23.625rem;
65
71
  color: var(--mdc-dialog-header-text-color);