@blockquote-web-components/blockquote-dialog 1.4.13 → 1.5.0

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.
package/README.md CHANGED
@@ -28,6 +28,12 @@ Inert content outside an active dialog is typically visually obscured or dimmed
28
28
 
29
29
  #### class: `BlockquoteDialog`, `blockquote-dialog`
30
30
 
31
+ ##### Static Fields
32
+
33
+ | Name | Privacy | Type | Default | Description | Inherited From |
34
+ | ------------------- | ------- | -------- | ----------------------------------------------------------------------- | ----------- | -------------- |
35
+ | `shadowRootOptions` | | `object` | `{ ...LitElement.shadowRootOptions, referenceTarget: 'inner-dialog', }` | | |
36
+
31
37
  ##### Fields
32
38
 
33
39
  | Name | Privacy | Type | Default | Description | Inherited From |
@@ -47,6 +53,7 @@ Inert content outside an active dialog is typically visually obscured or dimmed
47
53
  | `_lastFocusableChild` | | | `undefined` | | |
48
54
  | `_nextClickIsFromContent` | | `boolean` | `false` | | |
49
55
  | `_overflowRoot` | | | | | |
56
+ | `_nativeDialogOpenObserver` | | | `undefined` | | |
50
57
  | `type` | public | `string` | `'alert'` | The type of dialog for accessibility. Set this to \`alert\` to announce a
dialog as an alert dialog. | |
51
58
  | `label` | public | `string` | `''` | The 'label' attribute will be used as the 'aria-label' for the dialog | |
52
59
  | `labelledby` | public | `string` | `''` | The 'labelledby' attribute will be used as the 'aria-labelledby' for the dialog.
It will also be used to create a slot with the same 'id' and 'name'.
This slot is hidden by default and its 'name' and 'id' should correspond to the 'slot' attribute of an element in the Light DOM.
This connects the 'slot', 'name', and 'id' attributes of a slot to be used with ARIA relationships. | |
@@ -61,6 +68,7 @@ Inert content outside an active dialog is typically visually obscured or dimmed
61
68
  | `show` | | | | | |
62
69
  | `close` | | | | | |
63
70
  | `_handleSubmit` | | | `ev: SubmitEvent` | | |
71
+ | `_handleNativeOpen` | | | `records` | | |
64
72
  | `_handleOpen` | | | | | |
65
73
  | `_handleClose` | | | `ev: Event` | | |
66
74
  | `_handleCancel` | | | `ev: Event` | | |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blockquote-web-components/blockquote-dialog",
3
- "version": "1.4.13",
3
+ "version": "1.5.0",
4
4
  "description": "Webcomponent blockquote-dialog following open-wc recommendations",
5
5
  "keywords": [
6
6
  "lit",
@@ -118,18 +118,19 @@
118
118
  ]
119
119
  },
120
120
  "dependencies": {
121
- "@blockquote-web-components/blockquote-directive-ariaidref-slot": "^1.3.13",
121
+ "@blockquote-web-components/blockquote-directive-ariaidref-slot": "^1.3.15",
122
122
  "@blockquote/frontend-utilities": "^1.1.0",
123
- "lit": "^3.3.1"
123
+ "@lit-labs/observers": "^2.1.0",
124
+ "lit": "^3.3.2"
124
125
  },
125
126
  "devDependencies": {
126
- "@blockquote-web-components/blockquote-base-common-dev-dependencies": "^1.12.6",
127
- "@blockquote-web-components/blockquote-base-embedded-webview": "^1.13.13",
127
+ "@blockquote-web-components/blockquote-base-common-dev-dependencies": "^1.12.8",
128
+ "@blockquote-web-components/blockquote-base-embedded-webview": "^1.13.15",
128
129
  "@blockquote-web-components/blockquote-foundations-sass": "^1.1.8"
129
130
  },
130
131
  "publishConfig": {
131
132
  "access": "public"
132
133
  },
133
134
  "customElements": "custom-elements.json",
134
- "gitHead": "e51976ff34663ccf6848bfaa1efbd55cde17c55f"
135
+ "gitHead": "c7e3d2f930c1e35f8c96fd5472ecbb078d1d935f"
135
136
  }
@@ -1,5 +1,6 @@
1
1
  import {html, LitElement, nothing, isServer} from 'lit';
2
2
  import {ref, createRef} from 'lit/directives/ref.js';
3
+ import {MutationController} from '@lit-labs/observers/mutation-controller.js';
3
4
  import {blockquoteDirectiveAriaidrefSlot} from '@blockquote-web-components/blockquote-directive-ariaidref-slot';
4
5
  import {
5
6
  redispatchEvent,
@@ -14,6 +15,7 @@ import {styles as animations} from './styles/blockqoute-dialog-animations-styles
14
15
  // https://web.dev/learn/html/dialog
15
16
  // https://github.com/oscarmarina/material-web/blob/main/dialog/dialog.ts
16
17
  // https://a11y-dialog.netlify.app/
18
+ // https://blogs.igalia.com/alice/reference-target-having-your-encapsulation-and-eating-it-too/
17
19
 
18
20
  /**
19
21
  * ![Lit](https://img.shields.io/badge/lit-3.0.0-blue.svg)
@@ -63,6 +65,14 @@ export class BlockquoteDialog extends LitElement {
63
65
 
64
66
  dialogRef = createRef();
65
67
 
68
+ /**
69
+ * @override
70
+ */
71
+ static shadowRootOptions = {
72
+ ...LitElement.shadowRootOptions,
73
+ referenceTarget: 'inner-dialog',
74
+ };
75
+
66
76
  /**
67
77
  * @override
68
78
  */
@@ -113,7 +123,7 @@ export class BlockquoteDialog extends LitElement {
113
123
  * By default, it is set to 'hidden'.
114
124
  */
115
125
  labelledbyVisible: {
116
- type: String,
126
+ type: Boolean,
117
127
  attribute: 'labelledby-visibile',
118
128
  },
119
129
 
@@ -152,6 +162,7 @@ export class BlockquoteDialog extends LitElement {
152
162
  this._lastFocusableChild = undefined;
153
163
  this._nextClickIsFromContent = false;
154
164
  this._overflowRoot = document.body;
165
+ this._nativeDialogOpenObserver = undefined;
155
166
  this.type = 'alert';
156
167
  this.label = '';
157
168
  this.labelledby = '';
@@ -172,6 +183,7 @@ export class BlockquoteDialog extends LitElement {
172
183
  super.connectedCallback?.();
173
184
  await this.updateComplete;
174
185
  this.scroller = this.shadowRoot?.querySelector('.scroller');
186
+ const {value} = this.dialogRef;
175
187
  const [first, last] = getFirstAndLastFocusableChildren(
176
188
  /** @type {IterableIterator<HTMLElement>} */ (this.treewalker)
177
189
  );
@@ -180,28 +192,30 @@ export class BlockquoteDialog extends LitElement {
180
192
  this._lastFocusableChild = last;
181
193
  this.role = 'presentation';
182
194
 
195
+ this._nativeDialogOpenObserver = new MutationController(this, {
196
+ target: value,
197
+ config: {attributes: true},
198
+ skipInitial: true,
199
+ callback: this._handleNativeOpen.bind(this),
200
+ });
201
+
183
202
  this._isConnectedCallbackResolve();
184
203
  }
185
204
 
186
205
  disconnectedCallback() {
187
206
  super.disconnectedCallback();
188
- this.isConnectedPromise = this.getIsConnectedCallbackResolve();
207
+ this._isConnectedCallback = this.getIsConnectedCallbackResolve();
189
208
  }
190
209
 
191
210
  async show() {
192
211
  await this._isConnectedCallback;
193
212
  const {value} = this.dialogRef;
194
213
 
195
- if (/** @type {HTMLDialogElement} */ (value)?.open) {
196
- return;
197
- }
198
-
199
214
  const preventDefault = !this._handleOpen();
200
215
  if (preventDefault) {
201
216
  this.open = false;
202
217
  return;
203
218
  }
204
-
205
219
  /** @type {HTMLDialogElement} */ (value)?.showModal();
206
220
  this.requestUpdate();
207
221
 
@@ -280,14 +294,15 @@ export class BlockquoteDialog extends LitElement {
280
294
  render() {
281
295
  return html`
282
296
  <dialog
297
+ id="inner-dialog"
283
298
  ${ref(this.dialogRef)}
284
- aria-label=${this.label || nothing}
299
+ aria-label="${this.label || nothing}"
285
300
  aria-labelledby="${this.labelledby || nothing}"
286
- role=${this.type === 'alert' ? 'alertdialog' : nothing}
287
- @click=${this._handleDialogClick}
288
- @cancel=${this._handleCancel}
289
- @close=${this._handleClose}
290
- .returnValue=${this.returnValue || nothing}>
301
+ role="${this.type === 'alert' ? 'alertdialog' : nothing}"
302
+ @click="${this._handleDialogClick}"
303
+ @cancel="${this._handleCancel}"
304
+ @close="${this._handleClose}"
305
+ .returnValue="${this.returnValue || nothing}">
291
306
  ${this._firstNodeFocusTrapTpl} ${this._scrollerTpl} ${this._lastNodeFocusTrapTpl}
292
307
  </dialog>
293
308
  `;
@@ -310,6 +325,18 @@ export class BlockquoteDialog extends LitElement {
310
325
  this.open = false;
311
326
  }
312
327
 
328
+ _handleNativeOpen(/** @type {MutationRecord[]} */ records) {
329
+ const openMutation = records.find((record) => record.attributeName === 'open');
330
+ if (!openMutation) {
331
+ return;
332
+ }
333
+
334
+ const {value} = this.dialogRef;
335
+ if (/** @type {HTMLDialogElement} */ (value)?.open && !this.open) {
336
+ this.open = true;
337
+ }
338
+ }
339
+
313
340
  _handleOpen() {
314
341
  /**
315
342
  * Dispatched when the dialog is open.
@@ -372,11 +399,11 @@ export class BlockquoteDialog extends LitElement {
372
399
  this._nextClickIsFromContent = true;
373
400
  }
374
401
 
375
- _firstFocusTrap({relatedTarget}) {
402
+ _firstFocusTrap(/** @type {*} */ {relatedTarget}) {
376
403
  (relatedTarget != null ? this._firstFocusableChild : this._lastFocusableChild)?.focus();
377
404
  }
378
405
 
379
- _lastFocusTrap({relatedTarget}) {
406
+ _lastFocusTrap(/** @type {*} */ {relatedTarget}) {
380
407
  (relatedTarget != null ? this._lastFocusableChild : this._firstFocusableChild)?.focus();
381
408
  }
382
409
  }