@momentum-design/components 0.127.5 → 0.127.7

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.
@@ -78,7 +78,9 @@ declare class AnnouncementDialog extends Dialog {
78
78
  * The size of the announcement dialog, can be 'medium' (656px width), 'large' (992px width), 'xlarge' (90% width) or 'fullscreen' (100% width).
79
79
  * @default medium
80
80
  */
81
- size: AnnouncementDialogSize;
81
+ get size(): AnnouncementDialogSize;
82
+ set size(value: AnnouncementDialogSize);
83
+ constructor();
82
84
  connectedCallback(): void;
83
85
  protected renderHeader(): import("lit-html").TemplateResult<1>;
84
86
  protected renderBody(): import("lit-html").TemplateResult<1>;
@@ -80,13 +80,22 @@ import { DEFAULTS } from './announcementdialog.constants';
80
80
  * using the footer-link and footer-button slots is preferred
81
81
  */
82
82
  class AnnouncementDialog extends Dialog {
83
+ /**
84
+ * The size of the announcement dialog, can be 'medium' (656px width), 'large' (992px width), 'xlarge' (90% width) or 'fullscreen' (100% width).
85
+ * @default medium
86
+ */
87
+ get size() {
88
+ var _a, _b;
89
+ return ((_b = (_a = this.responsiveSettingsContext) === null || _a === void 0 ? void 0 : _a.value) === null || _b === void 0 ? void 0 : _b.forceFullscreenDialog)
90
+ ? 'fullscreen'
91
+ : this.internalSize;
92
+ }
93
+ set size(value) {
94
+ this.internalSize = value;
95
+ }
83
96
  constructor() {
84
- super(...arguments);
85
- /**
86
- * The size of the announcement dialog, can be 'medium' (656px width), 'large' (992px width), 'xlarge' (90% width) or 'fullscreen' (100% width).
87
- * @default medium
88
- */
89
- this.size = DEFAULTS.SIZE;
97
+ super();
98
+ this.internalSize = DEFAULTS.SIZE;
90
99
  }
91
100
  connectedCallback() {
92
101
  super.connectedCallback();
@@ -126,6 +135,7 @@ __decorate([
126
135
  ], AnnouncementDialog.prototype, "illustration", void 0);
127
136
  __decorate([
128
137
  property({ type: String, reflect: true }),
129
- __metadata("design:type", String)
130
- ], AnnouncementDialog.prototype, "size", void 0);
138
+ __metadata("design:type", String),
139
+ __metadata("design:paramtypes", [String])
140
+ ], AnnouncementDialog.prototype, "size", null);
131
141
  export default AnnouncementDialog;
@@ -75,6 +75,10 @@ declare const Dialog_base: import("../../utils/mixins/index.types").Constructor<
75
75
  * using the footer-link and footer-button slots is preferred
76
76
  */
77
77
  declare class Dialog extends Dialog_base {
78
+ /** @internal */
79
+ protected readonly responsiveSettingsContext: import("@lit/context").ContextConsumer<{
80
+ __context__: import("../responsivesettingsprovider/responsivesettingsprovider.types").ResponsiveSettings;
81
+ }, import("lit").ReactiveElement>;
78
82
  /**
79
83
  * The unique ID of the dialog
80
84
  */
@@ -99,11 +103,18 @@ declare class Dialog extends Dialog_base {
99
103
  * @default 1000
100
104
  */
101
105
  zIndex: number;
106
+ /**
107
+ * The internal value helps to restore original size when responsive settings disabled.
108
+ *
109
+ * @internal
110
+ */
111
+ protected internalSize: DialogSize;
102
112
  /**
103
113
  * The size of the dialog, can be 'small' (432px width), 'medium' (656px width), 'large' (992px width), 'xlarge' (90% width) or 'fullscreen' (100% width).
104
114
  * @default small
105
115
  */
106
- size: DialogSize;
116
+ get size(): DialogSize;
117
+ set size(value: DialogSize);
107
118
  /**
108
119
  * The variant of the dialog, can be 'default' or 'promotional'
109
120
  * @default default
@@ -17,6 +17,8 @@ import { TYPE, VALID_TEXT_TAGS } from '../text/text.constants';
17
17
  import { BUTTON_VARIANTS, ICON_BUTTON_SIZES } from '../button/button.constants';
18
18
  import { FooterMixin } from '../../utils/mixins/FooterMixin';
19
19
  import { BackdropMixin } from '../../utils/mixins/BackdropMixin';
20
+ import providerUtils from '../../utils/provider';
21
+ import ResponsiveSettingsProvider from '../responsivesettingsprovider';
20
22
  import { DEFAULTS } from './dialog.constants';
21
23
  import { DialogEventManager } from './dialog.events';
22
24
  import styles from './dialog.styles';
@@ -95,6 +97,13 @@ import styles from './dialog.styles';
95
97
  class Dialog extends BackdropMixin(PreventScrollMixin(FocusTrapMixin(FooterMixin(Component)))) {
96
98
  constructor() {
97
99
  super(...arguments);
100
+ /** @internal */
101
+ this.responsiveSettingsContext = providerUtils.consume({
102
+ host: this,
103
+ context: ResponsiveSettingsProvider.Context,
104
+ subscribe: true,
105
+ syncProperties: ['size'],
106
+ });
98
107
  /**
99
108
  * The unique ID of the dialog
100
109
  */
@@ -114,10 +123,11 @@ class Dialog extends BackdropMixin(PreventScrollMixin(FocusTrapMixin(FooterMixin
114
123
  */
115
124
  this.zIndex = DEFAULTS.Z_INDEX;
116
125
  /**
117
- * The size of the dialog, can be 'small' (432px width), 'medium' (656px width), 'large' (992px width), 'xlarge' (90% width) or 'fullscreen' (100% width).
118
- * @default small
126
+ * The internal value helps to restore original size when responsive settings disabled.
127
+ *
128
+ * @internal
119
129
  */
120
- this.size = DEFAULTS.SIZE;
130
+ this.internalSize = DEFAULTS.SIZE;
121
131
  /**
122
132
  * The variant of the dialog, can be 'default' or 'promotional'
123
133
  * @default default
@@ -202,6 +212,17 @@ class Dialog extends BackdropMixin(PreventScrollMixin(FocusTrapMixin(FooterMixin
202
212
  this.closeDialog();
203
213
  };
204
214
  }
215
+ /**
216
+ * The size of the dialog, can be 'small' (432px width), 'medium' (656px width), 'large' (992px width), 'xlarge' (90% width) or 'fullscreen' (100% width).
217
+ * @default small
218
+ */
219
+ get size() {
220
+ var _a, _b;
221
+ return ((_b = (_a = this.responsiveSettingsContext) === null || _a === void 0 ? void 0 : _a.value) === null || _b === void 0 ? void 0 : _b.forceFullscreenDialog) ? 'fullscreen' : this.internalSize;
222
+ }
223
+ set size(value) {
224
+ this.internalSize = value;
225
+ }
205
226
  connectedCallback() {
206
227
  super.connectedCallback();
207
228
  // event listener can be added to the element directly, since dialog is a modal component
@@ -450,8 +471,9 @@ __decorate([
450
471
  ], Dialog.prototype, "zIndex", void 0);
451
472
  __decorate([
452
473
  property({ type: String, reflect: true }),
453
- __metadata("design:type", String)
454
- ], Dialog.prototype, "size", void 0);
474
+ __metadata("design:type", String),
475
+ __metadata("design:paramtypes", [String])
476
+ ], Dialog.prototype, "size", null);
455
477
  __decorate([
456
478
  property({ type: String, reflect: true }),
457
479
  __metadata("design:type", String)
@@ -103,6 +103,11 @@ declare class ScreenreaderAnnouncer extends Component {
103
103
  * Clears all timeouts and removes all announcements from the screen reader.
104
104
  */
105
105
  private clearTimeOutsAndAnnouncements;
106
+ /**
107
+ * Gets an element by ID, searching in both light DOM and modal dialog shadow root.
108
+ * @internal
109
+ */
110
+ private getElementByIdAcrossShadowRoot;
106
111
  /**
107
112
  * Creates a div element with id as identity attribute in the DOM.
108
113
  *
@@ -110,6 +115,11 @@ declare class ScreenreaderAnnouncer extends Component {
110
115
  * `mdc-screenreaderannouncer-identity`.
111
116
  */
112
117
  private createAnnouncementAriaLiveRegion;
118
+ /**
119
+ * Finds the closest modal dialog ancestor, traversing through shadow DOM boundaries.
120
+ * @internal
121
+ */
122
+ private findModalAncestor;
113
123
  /**
114
124
  * Creates a single debounced function that will read the latest this.announcement when executed.
115
125
  *
@@ -118,15 +118,14 @@ class ScreenreaderAnnouncer extends Component {
118
118
  const announcementContainer = document.createElement('div');
119
119
  announcementContainer.setAttribute('id', announcementId);
120
120
  announcementContainer.setAttribute('aria-live', ariaLive);
121
- (_a = document.getElementById(this.identity)) === null || _a === void 0 ? void 0 : _a.appendChild(announcementContainer);
121
+ (_a = this.getElementByIdAcrossShadowRoot(this.identity)) === null || _a === void 0 ? void 0 : _a.appendChild(announcementContainer);
122
122
  const timeOutId = window.setTimeout(() => {
123
123
  const announcementElement = document.createElement('p');
124
124
  announcementElement.textContent = announcement;
125
125
  announcementContainer.appendChild(announcementElement);
126
126
  this.ariaLiveAnnouncementIds.push(announcementId);
127
127
  const timeOutId = window.setTimeout(() => {
128
- var _a;
129
- (_a = document.getElementById(announcementId)) === null || _a === void 0 ? void 0 : _a.remove();
128
+ announcementContainer.remove();
130
129
  }, timeout);
131
130
  this.timeOutIds.push(timeOutId);
132
131
  }, delay);
@@ -142,9 +141,22 @@ class ScreenreaderAnnouncer extends Component {
142
141
  });
143
142
  this.ariaLiveAnnouncementIds.forEach(announcementId => {
144
143
  var _a;
145
- (_a = document.getElementById(announcementId)) === null || _a === void 0 ? void 0 : _a.remove();
144
+ (_a = this.getElementByIdAcrossShadowRoot(announcementId)) === null || _a === void 0 ? void 0 : _a.remove();
146
145
  });
147
146
  }
147
+ /**
148
+ * Gets an element by ID, searching in both light DOM and modal dialog shadow root.
149
+ * @internal
150
+ */
151
+ getElementByIdAcrossShadowRoot(id) {
152
+ var _a;
153
+ const element = document.getElementById(id);
154
+ if (element) {
155
+ return element;
156
+ }
157
+ const modalDialog = this.findModalAncestor();
158
+ return ((_a = modalDialog === null || modalDialog === void 0 ? void 0 : modalDialog.shadowRoot) === null || _a === void 0 ? void 0 : _a.getElementById(id)) || null;
159
+ }
148
160
  /**
149
161
  * Creates a div element with id as identity attribute in the DOM.
150
162
  *
@@ -152,7 +164,7 @@ class ScreenreaderAnnouncer extends Component {
152
164
  * `mdc-screenreaderannouncer-identity`.
153
165
  */
154
166
  createAnnouncementAriaLiveRegion() {
155
- let liveRegionLightDom = document.getElementById(this.identity);
167
+ let liveRegionLightDom = this.getElementByIdAcrossShadowRoot(this.identity);
156
168
  if (!liveRegionLightDom) {
157
169
  liveRegionLightDom = document.createElement('div');
158
170
  liveRegionLightDom.id = this.identity;
@@ -170,8 +182,37 @@ class ScreenreaderAnnouncer extends Component {
170
182
  `;
171
183
  liveRegionLightDom.appendChild(styleElement);
172
184
  liveRegionLightDom.classList.add('mdc-screenreaderannouncer__visually-hidden');
173
- document.body.appendChild(liveRegionLightDom);
185
+ // If inside a modal dialog, append to its shadow root, otherwise to document.body
186
+ const modalDialog = this.findModalAncestor();
187
+ if (modalDialog === null || modalDialog === void 0 ? void 0 : modalDialog.shadowRoot) {
188
+ modalDialog.shadowRoot.appendChild(liveRegionLightDom);
189
+ }
190
+ else {
191
+ document.body.appendChild(liveRegionLightDom);
192
+ }
193
+ }
194
+ }
195
+ /**
196
+ * Finds the closest modal dialog ancestor, traversing through shadow DOM boundaries.
197
+ * @internal
198
+ */
199
+ findModalAncestor() {
200
+ let element = this;
201
+ while (element) {
202
+ const modal = element.closest('[aria-modal="true"]');
203
+ if (modal) {
204
+ return modal;
205
+ }
206
+ // Traverse up through shadow DOM boundary
207
+ const root = element.getRootNode();
208
+ if (root instanceof ShadowRoot && root.host) {
209
+ element = root.host;
210
+ }
211
+ else {
212
+ break;
213
+ }
174
214
  }
215
+ return null;
175
216
  }
176
217
  /**
177
218
  * Creates a single debounced function that will read the latest this.announcement when executed.
@@ -182,15 +182,6 @@ declare class Textarea extends Textarea_base {
182
182
  */
183
183
  handleValueChange(): void;
184
184
  protected updated(changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void;
185
- /**
186
- * This function is called when the attribute changes.
187
- * It updates the validity of the textarea field based on the textarea field's validity.
188
- *
189
- * @param name - attribute name
190
- * @param old - old value
191
- * @param value - new value
192
- */
193
- attributeChangedCallback(name: string, old: string | null, value: string | null): void;
194
185
  /**
195
186
  * Dispatches the character overflow state change event.
196
187
  * @returns void
@@ -265,28 +265,9 @@ class Textarea extends AutoFocusOnMountMixin(FormInternalsMixin(DataAriaLabelMix
265
265
  this.handleValueChange();
266
266
  this.handleCharacterOverflowStateChange();
267
267
  }
268
- }
269
- /**
270
- * This function is called when the attribute changes.
271
- * It updates the validity of the textarea field based on the textarea field's validity.
272
- *
273
- * @param name - attribute name
274
- * @param old - old value
275
- * @param value - new value
276
- */
277
- attributeChangedCallback(name, old, value) {
278
- super.attributeChangedCallback(name, old, value);
279
- const validationRelatedAttributes = ['maxlength', 'minlength', 'required'];
280
- if (validationRelatedAttributes.includes(name)) {
281
- this.updateComplete
282
- .then(() => {
283
- this.setTextareaValidity();
284
- })
285
- .catch(error => {
286
- if (this.onerror) {
287
- this.onerror(error);
288
- }
289
- });
268
+ // When helpText gets changed, we need to re-announce the max length warning
269
+ if (changedProperties.has('helpText')) {
270
+ this.announceMaxLengthWarning();
290
271
  }
291
272
  }
292
273
  /**
@@ -442,20 +423,23 @@ class Textarea extends AutoFocusOnMountMixin(FormInternalsMixin(DataAriaLabelMix
442
423
  identity="${this.inputId}"
443
424
  announcement="${ifDefined(this.ariaLiveAnnouncer)}"
444
425
  data-aria-live="polite"
426
+ delay="500"
445
427
  ></mdc-screenreaderannouncer>
446
- ${this.resizable ? html `
447
- <mdc-button
448
- part="resize-button"
449
- class="own-focus-ring"
450
- variant="tertiary"
451
- size="24"
452
- prefix-icon="resize-corner-regular"
453
- aria-label=${(_b = this.resizeButtonAriaLabel) !== null && _b !== void 0 ? _b : ''}
454
- ?disabled="${this.disabled || this.readonly}"
455
- @keydown=${this.handleResizeKeyDown}
456
- @pointerdown=${this.handlePointerDown}
457
- ></mdc-button>
458
- ` : nothing}
428
+ ${this.resizable
429
+ ? html `
430
+ <mdc-button
431
+ part="resize-button"
432
+ class="own-focus-ring"
433
+ variant="tertiary"
434
+ size="24"
435
+ prefix-icon="resize-corner-regular"
436
+ aria-label=${(_b = this.resizeButtonAriaLabel) !== null && _b !== void 0 ? _b : ''}
437
+ ?disabled="${this.disabled || this.readonly}"
438
+ @keydown=${this.handleResizeKeyDown}
439
+ @pointerdown=${this.handlePointerDown}
440
+ ></mdc-button>
441
+ `
442
+ : nothing}
459
443
  </div>
460
444
  ${this.renderTextareaFooter()}
461
445
  `;