@eunomia/elements 1.0.0-beta.7 → 1.0.0-beta.8

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.
Files changed (177) hide show
  1. package/dist/cdn/components/chunks/{chunk-3PNGQEG4.js → chunk-32L2QYWQ.js} +2 -2
  2. package/dist/cdn/components/chunks/{chunk-Z3OFIE7S.js → chunk-3UUZM7X2.js} +1 -1
  3. package/dist/cdn/components/chunks/{chunk-BVASCT2V.js → chunk-55PUDL7D.js} +13 -13
  4. package/dist/cdn/components/chunks/chunk-5LA5DQMP.js +1 -0
  5. package/dist/cdn/components/chunks/chunk-5LXGJVJR.js +1 -0
  6. package/dist/cdn/components/chunks/chunk-6TIEBY34.js +1 -0
  7. package/dist/cdn/components/chunks/{chunk-LVKMAHMU.js → chunk-AH2SKZ7T.js} +4 -1
  8. package/dist/cdn/components/chunks/chunk-JAGZL7JH.js +1 -0
  9. package/dist/cdn/components/chunks/{chunk-DGI7TKCU.js → chunk-LD35BFNK.js} +5 -9
  10. package/dist/cdn/components/chunks/chunk-P6LGU3FT.js +1 -0
  11. package/dist/cdn/components/chunks/{chunk-UYZR4JXZ.js → chunk-QSZO4GIH.js} +45 -9
  12. package/dist/cdn/components/chunks/{chunk-PXF554MD.js → chunk-QYB6Z6FG.js} +5 -5
  13. package/dist/cdn/components/chunks/{chunk-RIFF2D2F.js → chunk-RGC3I6MK.js} +1 -1
  14. package/dist/cdn/components/chunks/{chunk-N6ZW5CDN.js → chunk-TCSB2MLU.js} +1 -1
  15. package/dist/cdn/components/chunks/chunk-WIUERJII.js +1 -0
  16. package/dist/cdn/components/eun-animate.js +4 -4
  17. package/dist/cdn/components/eun-button.js +1 -1
  18. package/dist/cdn/components/eun-carousel.js +10 -9
  19. package/dist/cdn/components/eun-chip.js +17 -11
  20. package/dist/cdn/components/eun-collapse.js +1 -1
  21. package/dist/cdn/components/eun-color-picker.js +18 -5
  22. package/dist/cdn/components/eun-counter.js +10 -8
  23. package/dist/cdn/components/eun-date-picker.js +46 -43
  24. package/dist/cdn/components/eun-drawer.js +19 -20
  25. package/dist/cdn/components/eun-dropdown-button.js +1 -1
  26. package/dist/cdn/components/eun-dropdown-item.js +3 -3
  27. package/dist/cdn/components/eun-fab.js +1 -1
  28. package/dist/cdn/components/eun-image-carousel.js +4 -4
  29. package/dist/cdn/components/eun-input-phone.js +11 -8
  30. package/dist/cdn/components/eun-input.js +1 -1
  31. package/dist/cdn/components/eun-link.js +59 -13
  32. package/dist/cdn/components/eun-modal.js +23 -13
  33. package/dist/cdn/components/eun-scheduler-event-editor.js +1 -1
  34. package/dist/cdn/components/eun-search.js +34 -28
  35. package/dist/cdn/components/eun-select.js +3 -3
  36. package/dist/cdn/components/eun-sidebar.js +66 -21
  37. package/dist/cdn/components/eun-sliding-card.js +1 -1
  38. package/dist/cdn/components/eun-stepper.js +16 -16
  39. package/dist/cdn/components/eun-tab-panel.js +1 -1
  40. package/dist/cdn/components/eun-table-action-bar.js +1 -1
  41. package/dist/cdn/components/eun-table.js +2 -2
  42. package/dist/cdn/components/eun-textarea.js +16 -13
  43. package/dist/cdn/components/eun-time-picker.js +25 -23
  44. package/dist/cdn/components/eun-toast.js +8 -8
  45. package/dist/cdn/components/eun-toggle-group.js +71 -35
  46. package/dist/cdn/components/eun-toggle-item.js +8 -8
  47. package/dist/cdn/components/eun-toolbar.js +20 -20
  48. package/dist/cdn/components/eun-tooltip.js +6 -6
  49. package/dist/cdn/styles/eunomia-themes.css +1 -1
  50. package/dist/cdn/styles/themes/mixins/eunomia-neutrals.mixin.scss +6 -2
  51. package/dist/cdn/styles/themes/prebuilt-themes/eunomia/eunomia-dark.mixin.scss +6 -2
  52. package/dist/cdn/styles/themes/prebuilt-themes/eunomia/eunomia.theme.css +1 -1
  53. package/dist/cdn/styles/themes/prebuilt-themes/fire/eunomia-fire-dark.mixin.scss +6 -2
  54. package/dist/cdn/styles/themes/prebuilt-themes/fire/eunomia-fire.theme.css +1 -1
  55. package/dist/cdn/styles/themes/prebuilt-themes/forest/eunomia-forest-dark.mixin.scss +6 -2
  56. package/dist/cdn/styles/themes/prebuilt-themes/forest/eunomia-forest.theme.css +1 -1
  57. package/dist/cdn/styles/themes/prebuilt-themes/gold/eunomia-gold-dark.mixin.scss +6 -2
  58. package/dist/cdn/styles/themes/prebuilt-themes/gold/eunomia-gold.theme.css +1 -1
  59. package/dist/cdn/styles/themes/prebuilt-themes/ocean/eunomia-ocean-dark.mixin.scss +6 -2
  60. package/dist/cdn/styles/themes/prebuilt-themes/ocean/eunomia-ocean.theme.css +1 -1
  61. package/dist/cdn/styles/themes/prebuilt-themes/salmon/eunomia-salmon-dark.mixin.scss +6 -2
  62. package/dist/cdn/styles/themes/prebuilt-themes/salmon/eunomia-salmon.theme.css +1 -1
  63. package/dist/cdn/styles/themes/prebuilt-themes/violet/eunomia-violet-dark.mixin.scss +6 -2
  64. package/dist/cdn/styles/themes/prebuilt-themes/violet/eunomia-violet.theme.css +1 -1
  65. package/dist/components/action/button/button.d.ts +2 -2
  66. package/dist/components/action/button/button.js +3 -7
  67. package/dist/components/action/button/button.styles.js +3 -3
  68. package/dist/components/action/dropdown-button/dropdown-button.d.ts +4 -6
  69. package/dist/components/action/dropdown-button/dropdown-button.js +6 -8
  70. package/dist/components/action/dropdown-button/dropdown-item.d.ts +10 -2
  71. package/dist/components/action/dropdown-button/dropdown-item.js +24 -9
  72. package/dist/components/action/link/link.d.ts +10 -1
  73. package/dist/components/action/link/link.js +13 -1
  74. package/dist/components/action/link/link.styles.js +50 -3
  75. package/dist/components/action/toggle/toggle-group.d.ts +12 -2
  76. package/dist/components/action/toggle/toggle-group.js +17 -2
  77. package/dist/components/action/toggle/toggle-group.styles.js +54 -18
  78. package/dist/components/action/toggle/toggle-item.js +1 -3
  79. package/dist/components/action/toggle/toggle-item.styles.js +7 -7
  80. package/dist/components/alert/drawer/drawer.d.ts +25 -0
  81. package/dist/components/alert/drawer/drawer.js +42 -3
  82. package/dist/components/alert/drawer/drawer.styles.js +6 -6
  83. package/dist/components/alert/modal/modal.d.ts +25 -0
  84. package/dist/components/alert/modal/modal.js +42 -3
  85. package/dist/components/alert/modal/modal.styles.js +17 -6
  86. package/dist/components/alert/toast/toast.js +3 -2
  87. package/dist/components/alert/toast/toast.styles.js +3 -3
  88. package/dist/components/content/chip/chip.js +3 -2
  89. package/dist/components/content/chip/chip.styles.js +9 -3
  90. package/dist/components/content/image-carousel/image-carousel.js +5 -4
  91. package/dist/components/content/tooltip/tooltip.d.ts +16 -9
  92. package/dist/components/content/tooltip/tooltip.js +28 -12
  93. package/dist/components/content/tooltip/tooltip.styles.js +1 -1
  94. package/dist/components/form/color-picker/color-picker.d.ts +7 -1
  95. package/dist/components/form/color-picker/color-picker.js +8 -2
  96. package/dist/components/form/color-picker/color-picker.styles.js +13 -0
  97. package/dist/components/form/counter/counter.d.ts +3 -1
  98. package/dist/components/form/counter/counter.js +3 -1
  99. package/dist/components/form/counter/counter.styles.js +6 -4
  100. package/dist/components/form/date-picker/date-picker.d.ts +6 -1
  101. package/dist/components/form/date-picker/date-picker.js +7 -2
  102. package/dist/components/form/date-picker/date-picker.styles.js +9 -6
  103. package/dist/components/form/input/input.d.ts +6 -1
  104. package/dist/components/form/input/input.js +7 -2
  105. package/dist/components/form/input-phone/input-phone.d.ts +7 -1
  106. package/dist/components/form/input-phone/input-phone.js +7 -1
  107. package/dist/components/form/input-phone/input-phone.styles.js +6 -3
  108. package/dist/components/form/search/search.d.ts +64 -10
  109. package/dist/components/form/search/search.js +112 -31
  110. package/dist/components/form/search/search.styles.js +2 -0
  111. package/dist/components/form/select/select.d.ts +7 -1
  112. package/dist/components/form/select/select.js +7 -1
  113. package/dist/components/form/shared-styles/field.styles.js +45 -8
  114. package/dist/components/form/shared-styles/listbox.styles.js +5 -1
  115. package/dist/components/form/textarea/textarea.d.ts +1 -0
  116. package/dist/components/form/textarea/textarea.js +2 -1
  117. package/dist/components/form/textarea/textarea.styles.js +3 -0
  118. package/dist/components/form/time-picker/time-picker.d.ts +6 -1
  119. package/dist/components/form/time-picker/time-picker.js +7 -2
  120. package/dist/components/form/time-picker/time-picker.styles.js +7 -5
  121. package/dist/components/layout/animate/animate.js +2 -1
  122. package/dist/components/navigation/carousel/carousel.d.ts +1 -2
  123. package/dist/components/navigation/carousel/carousel.js +14 -6
  124. package/dist/components/navigation/carousel/carousel.styles.js +5 -4
  125. package/dist/components/navigation/sidebar/sidebar.d.ts +98 -52
  126. package/dist/components/navigation/sidebar/sidebar.js +140 -85
  127. package/dist/components/navigation/sidebar/sidebar.styles.d.ts +1 -1
  128. package/dist/components/navigation/sidebar/sidebar.styles.js +69 -21
  129. package/dist/components/navigation/stepper/stepper.d.ts +1 -3
  130. package/dist/components/navigation/stepper/stepper.js +3 -21
  131. package/dist/components/navigation/toolbar/toolbar.d.ts +10 -0
  132. package/dist/components/navigation/toolbar/toolbar.js +8 -1
  133. package/dist/components/navigation/toolbar/toolbar.styles.js +18 -17
  134. package/dist/events/select.event.d.ts +3 -2
  135. package/dist/events/select.event.js +2 -1
  136. package/dist/features/scheduler/scheduler-event-editor/scheduler-event-editor.js +1 -1
  137. package/dist/features/table/table/table.js +1 -1
  138. package/dist/features/table/table-action-bar/table-action-bar.js +2 -2
  139. package/dist/index.d.ts +1 -0
  140. package/dist/mixins/button.mixin.d.ts +1 -1
  141. package/dist/mixins/button.mixin.js +6 -4
  142. package/dist/mixins/dialog-surface.mixin.d.ts +8 -0
  143. package/dist/mixins/field-size.mixin.d.ts +19 -0
  144. package/dist/mixins/field-size.mixin.js +33 -0
  145. package/dist/mixins/rounded.mixin.d.ts +18 -0
  146. package/dist/mixins/rounded.mixin.js +32 -0
  147. package/dist/ssr/button-ssr.css +5 -5
  148. package/dist/ssr/carousel-ssr.css +9 -0
  149. package/dist/ssr/chip-ssr.css +8 -0
  150. package/dist/ssr/collapse-ssr.css +29 -0
  151. package/dist/ssr/field-ssr.css +43 -4
  152. package/dist/ssr/image-carousel-ssr.css +10 -0
  153. package/dist/ssr/links-ssr.css +38 -1
  154. package/dist/ssr/sidebar-ssr.css +95 -4
  155. package/dist/ssr/toggle-group-ssr.css +64 -13
  156. package/dist/ssr/toolbar-ssr.css +50 -0
  157. package/dist/types/variant.type.d.ts +4 -1
  158. package/dist/utils/boolean.utils.d.ts +14 -0
  159. package/dist/utils/boolean.utils.js +20 -0
  160. package/dist/utils/dropdown-menu.utils.d.ts +1 -1
  161. package/dist/utils/focusable-elements.utils.d.ts +12 -0
  162. package/dist/utils/focusable-elements.utils.js +26 -0
  163. package/dist/utils/input-modality.utils.d.ts +13 -0
  164. package/dist/utils/input-modality.utils.js +34 -0
  165. package/dist/utils/theme-generator.utils.d.ts +8 -2
  166. package/dist/utils/theme-generator.utils.js +30 -9
  167. package/package.json +1 -1
  168. package/styles/themes/mixins/eunomia-neutrals.mixin.scss +6 -2
  169. package/styles/themes/prebuilt-themes/eunomia/eunomia-dark.mixin.scss +6 -2
  170. package/styles/themes/prebuilt-themes/fire/eunomia-fire-dark.mixin.scss +6 -2
  171. package/styles/themes/prebuilt-themes/forest/eunomia-forest-dark.mixin.scss +6 -2
  172. package/styles/themes/prebuilt-themes/gold/eunomia-gold-dark.mixin.scss +6 -2
  173. package/styles/themes/prebuilt-themes/ocean/eunomia-ocean-dark.mixin.scss +6 -2
  174. package/styles/themes/prebuilt-themes/salmon/eunomia-salmon-dark.mixin.scss +6 -2
  175. package/styles/themes/prebuilt-themes/violet/eunomia-violet-dark.mixin.scss +6 -2
  176. package/dist/cdn/components/chunks/chunk-6VK6SHCG.js +0 -1
  177. package/dist/cdn/components/chunks/chunk-UDOZRIJZ.js +0 -1
@@ -1,4 +1,5 @@
1
1
  import { LitElement, PropertyValues, TemplateResult } from "lit";
2
+ import { EunomiaDialogInitialFocus } from "../../../mixins/dialog-surface.mixin.js";
2
3
  /**
3
4
  * Tag name of the drawer component.
4
5
  */
@@ -32,6 +33,7 @@ declare const EunomiaDrawer_base: import("../../../utils/constructor.type.js").C
32
33
  * @prop {boolean} [open=false] - Whether the drawer is open
33
34
  * @prop {boolean} [closeOnBackdrop=true] - Whether clicking outside the drawer requests a close
34
35
  * @prop {boolean} [dirty=false] - Marks the drawer as having unsaved changes, requiring confirmation before it closes
36
+ * @prop {'auto' | 'first-field'} [initialFocus='auto'] - Where focus lands on open. First-field focuses the first focusable element of the body when the drawer was opened from the keyboard, and behaves like auto after a click or a touch, so a mobile virtual keyboard doesn't pop up on its own. A slotted autofocus element always wins
35
37
  * @prop {string} [closeLabel] - The accessible label of the close button. Defaults to the localized string for the current locale (English: "Close")
36
38
  * @attr {string} [close-label] - The accessible label of the close button. Defaults to the localized string for the current locale (English: "Close")
37
39
  * @prop {string} [confirmCloseHeading='Discard changes?'] - The heading of the internal discard confirmation dialog
@@ -52,6 +54,7 @@ declare const EunomiaDrawer_base: import("../../../utils/constructor.type.js").C
52
54
  * @cssprop [--drawer-padding-block] - Sets the vertical padding, as one length applied to both sides. Ignored when --drawer-padding is set
53
55
  * @cssprop [--drawer-padding-inline] - Sets the horizontal padding, as one length applied to both sides. Ignored when --drawer-padding is set
54
56
  * @cssprop [--drawer-gap] - Sets the gap inside the header and footer rows
57
+ * @cssprop [--drawer-header-padding-bottom] - Sets the padding below the header, --drawer-gap by default
55
58
  * @cssprop [--drawer-transition-duration] - Sets the duration of the slide transition
56
59
  * @element eun-drawer
57
60
  */
@@ -96,6 +99,21 @@ export declare class EunomiaDrawer extends EunomiaDrawer_base {
96
99
  * @default false
97
100
  */
98
101
  dirty: boolean;
102
+ /**
103
+ * Where focus lands on open. `auto` keeps the default target described
104
+ * on {@link focusInitialElement}. `first-field` focuses the first
105
+ * focusable element of the body when the drawer was opened from the
106
+ * keyboard, and behaves like `auto` after a click or a touch, so a
107
+ * mobile virtual keyboard doesn't pop up on its own. A slotted
108
+ * `[autofocus]` element always wins.
109
+ * @default auto
110
+ */
111
+ initialFocus: EunomiaDialogInitialFocus;
112
+ /**
113
+ * The body wrapping the default slot, searched by `initial-focus="first-field"`.
114
+ * @internal
115
+ */
116
+ private readonly bodyEl?;
99
117
  /**
100
118
  * Accessible label of the close (X) button.
101
119
  * Falls back to the localized string for the current locale when unset.
@@ -252,6 +270,13 @@ export declare class EunomiaDrawer extends EunomiaDrawer_base {
252
270
  * @private
253
271
  */
254
272
  private readonly handleDiscardConfirmed;
273
+ /**
274
+ * Focuses the body's first focusable element when `initialFocus` is
275
+ * `first-field` and the latest interaction came from the keyboard.
276
+ * @returns whether an element was focused.
277
+ * @private
278
+ */
279
+ private focusFirstField;
255
280
  /**
256
281
  * Focuses the `[autofocus]` slotted element if present, otherwise the
257
282
  * drawer panel itself.
@@ -10,9 +10,12 @@ import { ifDefined } from "lit/directives/if-defined.js";
10
10
  import { DialogCancelEvent } from "../../../events/dialog-cancel.event.js";
11
11
  import { DirtyCloseEvent } from "../../../events/dirty-close.event.js";
12
12
  import { handleDialogCommand } from "../../../utils/command.utils.js";
13
- import { DialogSurfaceMixin } from "../../../mixins/dialog-surface.mixin.js";
13
+ import { DialogSurfaceMixin, } from "../../../mixins/dialog-surface.mixin.js";
14
+ import { getFocusableElements } from "../../../utils/focusable-elements.utils.js";
15
+ import { isKeyboardModality, trackInputModality, } from "../../../utils/input-modality.utils.js";
14
16
  import { drawerStyles } from "./drawer.styles.js";
15
17
  import { LocalizableMixin } from "../../../mixins/localizable.mixin.js";
18
+ import { defaultTrueConverter } from "../../../utils/boolean.utils.js";
16
19
  /**
17
20
  * Tag name of the drawer component.
18
21
  */
@@ -41,6 +44,7 @@ export const EunomiaDrawerTagName = "eun-drawer";
41
44
  * @prop {boolean} [open=false] - Whether the drawer is open
42
45
  * @prop {boolean} [closeOnBackdrop=true] - Whether clicking outside the drawer requests a close
43
46
  * @prop {boolean} [dirty=false] - Marks the drawer as having unsaved changes, requiring confirmation before it closes
47
+ * @prop {'auto' | 'first-field'} [initialFocus='auto'] - Where focus lands on open. First-field focuses the first focusable element of the body when the drawer was opened from the keyboard, and behaves like auto after a click or a touch, so a mobile virtual keyboard doesn't pop up on its own. A slotted autofocus element always wins
44
48
  * @prop {string} [closeLabel] - The accessible label of the close button. Defaults to the localized string for the current locale (English: "Close")
45
49
  * @attr {string} [close-label] - The accessible label of the close button. Defaults to the localized string for the current locale (English: "Close")
46
50
  * @prop {string} [confirmCloseHeading='Discard changes?'] - The heading of the internal discard confirmation dialog
@@ -61,6 +65,7 @@ export const EunomiaDrawerTagName = "eun-drawer";
61
65
  * @cssprop [--drawer-padding-block] - Sets the vertical padding, as one length applied to both sides. Ignored when --drawer-padding is set
62
66
  * @cssprop [--drawer-padding-inline] - Sets the horizontal padding, as one length applied to both sides. Ignored when --drawer-padding is set
63
67
  * @cssprop [--drawer-gap] - Sets the gap inside the header and footer rows
68
+ * @cssprop [--drawer-header-padding-bottom] - Sets the padding below the header, --drawer-gap by default
64
69
  * @cssprop [--drawer-transition-duration] - Sets the duration of the slide transition
65
70
  * @element eun-drawer
66
71
  */
@@ -94,6 +99,16 @@ let EunomiaDrawer = class EunomiaDrawer extends DialogSurfaceMixin(LocalizableMi
94
99
  * @default false
95
100
  */
96
101
  this.dirty = false;
102
+ /**
103
+ * Where focus lands on open. `auto` keeps the default target described
104
+ * on {@link focusInitialElement}. `first-field` focuses the first
105
+ * focusable element of the body when the drawer was opened from the
106
+ * keyboard, and behaves like `auto` after a click or a touch, so a
107
+ * mobile virtual keyboard doesn't pop up on its own. A slotted
108
+ * `[autofocus]` element always wins.
109
+ * @default auto
110
+ */
111
+ this.initialFocus = "auto";
97
112
  /**
98
113
  * Heading of the internal discard-confirmation dialog.
99
114
  * @default Discard changes?
@@ -229,6 +244,7 @@ let EunomiaDrawer = class EunomiaDrawer extends DialogSurfaceMixin(LocalizableMi
229
244
  */
230
245
  connectedCallback() {
231
246
  super.connectedCallback?.();
247
+ trackInputModality();
232
248
  this.addEventListener("command", this.handleCommandEvent);
233
249
  }
234
250
  /**
@@ -323,6 +339,20 @@ let EunomiaDrawer = class EunomiaDrawer extends DialogSurfaceMixin(LocalizableMi
323
339
  this.dirty = false;
324
340
  this.attemptClose();
325
341
  }
342
+ /**
343
+ * Focuses the body's first focusable element when `initialFocus` is
344
+ * `first-field` and the latest interaction came from the keyboard.
345
+ * @returns whether an element was focused.
346
+ * @private
347
+ */
348
+ focusFirstField() {
349
+ if (this.initialFocus !== "first-field" || !isKeyboardModality()) {
350
+ return false;
351
+ }
352
+ const [first] = this.bodyEl ? getFocusableElements(this.bodyEl) : [];
353
+ first?.focus();
354
+ return first !== undefined;
355
+ }
326
356
  /**
327
357
  * Focuses the `[autofocus]` slotted element if present, otherwise the
328
358
  * drawer panel itself.
@@ -334,6 +364,9 @@ let EunomiaDrawer = class EunomiaDrawer extends DialogSurfaceMixin(LocalizableMi
334
364
  autofocusTarget.focus();
335
365
  return;
336
366
  }
367
+ if (this.focusFirstField()) {
368
+ return;
369
+ }
337
370
  (this.panelEl ?? this.surfaceEl)?.focus();
338
371
  }
339
372
  /**
@@ -493,17 +526,23 @@ __decorate([
493
526
  property()
494
527
  ], EunomiaDrawer.prototype, "heading", void 0);
495
528
  __decorate([
496
- property({ type: Boolean })
529
+ property({ converter: defaultTrueConverter })
497
530
  ], EunomiaDrawer.prototype, "closeable", void 0);
498
531
  __decorate([
499
532
  property({ type: Boolean, reflect: true })
500
533
  ], EunomiaDrawer.prototype, "open", void 0);
501
534
  __decorate([
502
- property({ type: Boolean, attribute: "close-on-backdrop" })
535
+ property({ converter: defaultTrueConverter, attribute: "close-on-backdrop" })
503
536
  ], EunomiaDrawer.prototype, "closeOnBackdrop", void 0);
504
537
  __decorate([
505
538
  property({ type: Boolean, reflect: true })
506
539
  ], EunomiaDrawer.prototype, "dirty", void 0);
540
+ __decorate([
541
+ property({ attribute: "initial-focus", reflect: true, useDefault: true })
542
+ ], EunomiaDrawer.prototype, "initialFocus", void 0);
543
+ __decorate([
544
+ query("#body")
545
+ ], EunomiaDrawer.prototype, "bodyEl", void 0);
507
546
  __decorate([
508
547
  property({ attribute: "close-label" })
509
548
  ], EunomiaDrawer.prototype, "closeLabel", void 0);
@@ -11,6 +11,7 @@ import { css } from "lit";
11
11
  * [--drawer-padding-block] - Set a custom vertical padding, as one length applied to both sides. Ignored when --drawer-padding is set
12
12
  * [--drawer-padding-inline] - Set a custom horizontal padding, as one length applied to both sides. Ignored when --drawer-padding is set
13
13
  * [--drawer-gap] - Set a custom gap inside the header/footer rows
14
+ * [--drawer-header-padding-bottom] - Set a custom padding below the header, --drawer-gap by default
14
15
  * [--drawer-transition-duration] - Set a custom duration for the slide transition
15
16
  */
16
17
  const base = css `
@@ -20,11 +21,11 @@ const base = css `
20
21
  --_color: var(--drawer-color, var(--eun-text-color, #071621));
21
22
  --_paddingBlock: var(
22
23
  --drawer-padding,
23
- var(--drawer-padding-block, var(--eun-space-m, 16px))
24
+ var(--drawer-padding-block, var(--eun-space-l, 32px))
24
25
  );
25
26
  --_paddingInline: var(
26
27
  --drawer-padding,
27
- var(--drawer-padding-inline, var(--eun-space-m, 16px))
28
+ var(--drawer-padding-inline, var(--eun-space-l, 32px))
28
29
  );
29
30
  --_gap: var(--drawer-gap, var(--eun-space-m, 16px));
30
31
  --_transitionDuration: var(
@@ -117,7 +118,8 @@ const base = css `
117
118
  align-items: flex-start;
118
119
  justify-content: space-between;
119
120
  gap: var(--_gap);
120
- padding: var(--_paddingBlock) var(--_paddingInline) 0;
121
+ padding: var(--_paddingBlock) var(--_paddingInline)
122
+ var(--drawer-header-padding-bottom, var(--_gap));
121
123
  }
122
124
  #heading {
123
125
  margin: 0;
@@ -132,7 +134,7 @@ const base = css `
132
134
  flex: 1;
133
135
  min-height: 0;
134
136
  overflow-y: auto;
135
- padding: var(--_gap) var(--_paddingInline);
137
+ padding: var(--eun-space-xs, 4px) var(--_paddingInline);
136
138
  font-size: var(--eun-font-size-s, 14px);
137
139
  }
138
140
  #footer {
@@ -144,8 +146,6 @@ const base = css `
144
146
  }
145
147
 
146
148
  #confirm-close-modal {
147
- --modal-padding: var(--eun-space-l, 32px) var(--eun-space-m, 16px)
148
- var(--eun-space-m, 16px) var(--eun-space-l, 32px);
149
149
  --modal-gap: var(--eun-space-m, 16px);
150
150
  --modal-backdrop-blur: 6px;
151
151
  }
@@ -1,4 +1,5 @@
1
1
  import { LitElement, PropertyValues, TemplateResult } from "lit";
2
+ import { EunomiaDialogInitialFocus } from "../../../mixins/dialog-surface.mixin.js";
2
3
  import { ButtonColor } from "../../../mixins/button.mixin.js";
3
4
  import { EunomiaModalConfirmColor } from "../../../types/variant.type.js";
4
5
  /**
@@ -31,6 +32,7 @@ declare const EunomiaModal_base: import("../../../utils/constructor.type.js").Co
31
32
  * @prop {boolean} [closeOnBackdrop=true] - Whether clicking outside the dialog requests a close, subject to the dirty gate
32
33
  * @prop {boolean} [dirty=false] - Marks the modal as having unsaved changes, requiring confirmation before any close attempt succeeds
33
34
  * @prop {boolean} [hideActions=false] - Hides the default confirm and cancel footer entirely, for fully custom content-driven dialogs
35
+ * @prop {'auto' | 'first-field'} [initialFocus='auto'] - Where focus lands on open. First-field focuses the first focusable element of the body when the modal was opened from the keyboard, and behaves like auto after a click or a touch, so a mobile virtual keyboard doesn't pop up on its own. A slotted autofocus element always wins
34
36
  * @prop {boolean} [closeable=true] - Shows the close button in the top right corner
35
37
  * @prop {string} [cancelLabel] - The label of the default cancel button. Defaults to the localized string for the current locale (English: "Cancel")
36
38
  * @prop {string} [confirmLabel] - The label of the default confirm button. Defaults to the localized string for the current locale (English: "Confirm")
@@ -53,6 +55,7 @@ declare const EunomiaModal_base: import("../../../utils/constructor.type.js").Co
53
55
  * @cssprop [--modal-padding] - Sets the padding of the dialog panel
54
56
  * @cssprop [--modal-padding-block] - Sets the vertical padding, as one length applied to both sides. Ignored when --modal-padding is set
55
57
  * @cssprop [--modal-padding-inline] - Sets the horizontal padding, as one length applied to both sides. Ignored when --modal-padding is set
58
+ * @cssprop [--modal-close-offset] - Sets the distance from the top and inline-end edges of the dialog panel to the close button, aligned on the panel padding by default
56
59
  * @cssprop [--modal-gap] - Sets the gap between the heading, body, and actions blocks
57
60
  * @cssprop [--modal-border-radius] - Sets the corner radius of the dialog panel
58
61
  * @cssprop [--modal-background] - Sets the background color of the dialog panel
@@ -108,6 +111,21 @@ export declare class EunomiaModal extends EunomiaModal_base {
108
111
  * @default false
109
112
  */
110
113
  hideActions: boolean;
114
+ /**
115
+ * Where focus lands on open. `auto` keeps the default target described
116
+ * on {@link focusInitialElement}. `first-field` focuses the first
117
+ * focusable element of the body when the modal was opened from the
118
+ * keyboard, and behaves like `auto` after a click or a touch, so a
119
+ * mobile virtual keyboard doesn't pop up on its own. A slotted
120
+ * `[autofocus]` element always wins.
121
+ * @default auto
122
+ */
123
+ initialFocus: EunomiaDialogInitialFocus;
124
+ /**
125
+ * The body wrapping the default slot, searched by `initial-focus="first-field"`.
126
+ * @internal
127
+ */
128
+ private readonly bodyEl?;
111
129
  /**
112
130
  * Shows the top-right close (X) button.
113
131
  * @default true
@@ -305,6 +323,13 @@ export declare class EunomiaModal extends EunomiaModal_base {
305
323
  * @private
306
324
  */
307
325
  private readonly stopDialogPropagation;
326
+ /**
327
+ * Focuses the body's first focusable element when `initialFocus` is
328
+ * `first-field` and the latest interaction came from the keyboard.
329
+ * @returns whether an element was focused.
330
+ * @private
331
+ */
332
+ private focusFirstField;
308
333
  /**
309
334
  * Focuses the `[autofocus]` slotted element if present, otherwise the
310
335
  * cancel button, otherwise the dialog surface itself.
@@ -11,9 +11,12 @@ import { ConfirmEvent } from "../../../events/confirm.event.js";
11
11
  import { DialogCancelEvent } from "../../../events/dialog-cancel.event.js";
12
12
  import { DirtyCloseEvent } from "../../../events/dirty-close.event.js";
13
13
  import { handleDialogCommand } from "../../../utils/command.utils.js";
14
- import { DialogSurfaceMixin } from "../../../mixins/dialog-surface.mixin.js";
14
+ import { DialogSurfaceMixin, } from "../../../mixins/dialog-surface.mixin.js";
15
+ import { getFocusableElements } from "../../../utils/focusable-elements.utils.js";
16
+ import { isKeyboardModality, trackInputModality, } from "../../../utils/input-modality.utils.js";
15
17
  import { modalStyles } from "./modal.styles.js";
16
18
  import { LocalizableMixin } from "../../../mixins/localizable.mixin.js";
19
+ import { defaultTrueConverter } from "../../../utils/boolean.utils.js";
17
20
  /**
18
21
  * Tag name of the modal component.
19
22
  */
@@ -43,6 +46,7 @@ export const EunomiaModalTagName = "eun-modal";
43
46
  * @prop {boolean} [closeOnBackdrop=true] - Whether clicking outside the dialog requests a close, subject to the dirty gate
44
47
  * @prop {boolean} [dirty=false] - Marks the modal as having unsaved changes, requiring confirmation before any close attempt succeeds
45
48
  * @prop {boolean} [hideActions=false] - Hides the default confirm and cancel footer entirely, for fully custom content-driven dialogs
49
+ * @prop {'auto' | 'first-field'} [initialFocus='auto'] - Where focus lands on open. First-field focuses the first focusable element of the body when the modal was opened from the keyboard, and behaves like auto after a click or a touch, so a mobile virtual keyboard doesn't pop up on its own. A slotted autofocus element always wins
46
50
  * @prop {boolean} [closeable=true] - Shows the close button in the top right corner
47
51
  * @prop {string} [cancelLabel] - The label of the default cancel button. Defaults to the localized string for the current locale (English: "Cancel")
48
52
  * @prop {string} [confirmLabel] - The label of the default confirm button. Defaults to the localized string for the current locale (English: "Confirm")
@@ -65,6 +69,7 @@ export const EunomiaModalTagName = "eun-modal";
65
69
  * @cssprop [--modal-padding] - Sets the padding of the dialog panel
66
70
  * @cssprop [--modal-padding-block] - Sets the vertical padding, as one length applied to both sides. Ignored when --modal-padding is set
67
71
  * @cssprop [--modal-padding-inline] - Sets the horizontal padding, as one length applied to both sides. Ignored when --modal-padding is set
72
+ * @cssprop [--modal-close-offset] - Sets the distance from the top and inline-end edges of the dialog panel to the close button, aligned on the panel padding by default
68
73
  * @cssprop [--modal-gap] - Sets the gap between the heading, body, and actions blocks
69
74
  * @cssprop [--modal-border-radius] - Sets the corner radius of the dialog panel
70
75
  * @cssprop [--modal-background] - Sets the background color of the dialog panel
@@ -107,6 +112,16 @@ let EunomiaModal = class EunomiaModal extends DialogSurfaceMixin(LocalizableMixi
107
112
  * @default false
108
113
  */
109
114
  this.hideActions = false;
115
+ /**
116
+ * Where focus lands on open. `auto` keeps the default target described
117
+ * on {@link focusInitialElement}. `first-field` focuses the first
118
+ * focusable element of the body when the modal was opened from the
119
+ * keyboard, and behaves like `auto` after a click or a touch, so a
120
+ * mobile virtual keyboard doesn't pop up on its own. A slotted
121
+ * `[autofocus]` element always wins.
122
+ * @default auto
123
+ */
124
+ this.initialFocus = "auto";
110
125
  /**
111
126
  * Shows the top-right close (X) button.
112
127
  * @default true
@@ -248,6 +263,7 @@ let EunomiaModal = class EunomiaModal extends DialogSurfaceMixin(LocalizableMixi
248
263
  */
249
264
  connectedCallback() {
250
265
  super.connectedCallback?.();
266
+ trackInputModality();
251
267
  this.addEventListener("command", this.handleCommandEvent);
252
268
  }
253
269
  /**
@@ -351,6 +367,20 @@ let EunomiaModal = class EunomiaModal extends DialogSurfaceMixin(LocalizableMixi
351
367
  this.dirty = false;
352
368
  this.cancel();
353
369
  }
370
+ /**
371
+ * Focuses the body's first focusable element when `initialFocus` is
372
+ * `first-field` and the latest interaction came from the keyboard.
373
+ * @returns whether an element was focused.
374
+ * @private
375
+ */
376
+ focusFirstField() {
377
+ if (this.initialFocus !== "first-field" || !isKeyboardModality()) {
378
+ return false;
379
+ }
380
+ const [first] = this.bodyEl ? getFocusableElements(this.bodyEl) : [];
381
+ first?.focus();
382
+ return first !== undefined;
383
+ }
354
384
  /**
355
385
  * Focuses the `[autofocus]` slotted element if present, otherwise the
356
386
  * cancel button, otherwise the dialog surface itself.
@@ -362,6 +392,9 @@ let EunomiaModal = class EunomiaModal extends DialogSurfaceMixin(LocalizableMixi
362
392
  autofocusTarget.focus();
363
393
  return;
364
394
  }
395
+ if (this.focusFirstField()) {
396
+ return;
397
+ }
365
398
  if (!this.hideActions) {
366
399
  this.cancelButtonEl?.focus();
367
400
  return;
@@ -493,7 +526,7 @@ __decorate([
493
526
  property({ reflect: true, useDefault: true })
494
527
  ], EunomiaModal.prototype, "kind", void 0);
495
528
  __decorate([
496
- property({ type: Boolean, attribute: "close-on-backdrop" })
529
+ property({ converter: defaultTrueConverter, attribute: "close-on-backdrop" })
497
530
  ], EunomiaModal.prototype, "closeOnBackdrop", void 0);
498
531
  __decorate([
499
532
  property({ type: Boolean, reflect: true })
@@ -502,7 +535,13 @@ __decorate([
502
535
  property({ type: Boolean, attribute: "hide-actions" })
503
536
  ], EunomiaModal.prototype, "hideActions", void 0);
504
537
  __decorate([
505
- property({ type: Boolean, reflect: true })
538
+ property({ attribute: "initial-focus", reflect: true, useDefault: true })
539
+ ], EunomiaModal.prototype, "initialFocus", void 0);
540
+ __decorate([
541
+ query("#body")
542
+ ], EunomiaModal.prototype, "bodyEl", void 0);
543
+ __decorate([
544
+ property({ converter: defaultTrueConverter, reflect: true })
506
545
  ], EunomiaModal.prototype, "closeable", void 0);
507
546
  __decorate([
508
547
  property({ attribute: "cancel-label" })
@@ -8,6 +8,7 @@ import { css } from "lit";
8
8
  * [--modal-padding] - Set a custom padding to the dialog panel
9
9
  * [--modal-padding-block] - Set a custom vertical padding, as one length applied to both sides. Ignored when --modal-padding is set
10
10
  * [--modal-padding-inline] - Set a custom horizontal padding, as one length applied to both sides. Ignored when --modal-padding is set
11
+ * [--modal-close-offset] - Set a custom distance from the top and inline-end edges of the dialog panel to the close button
11
12
  * [--modal-gap] - Set a custom gap between the heading/body/actions blocks
12
13
  * [--modal-border-radius] - Set a custom border radius to the dialog panel
13
14
  * [--modal-background] - Set a custom background color to the dialog panel
@@ -19,6 +20,8 @@ import { css } from "lit";
19
20
  const base = css `
20
21
  :host {
21
22
  display: contents;
23
+ /* Rendered width of the size="xs" close button. */
24
+ --_closeButtonSize: 26px;
22
25
  }
23
26
  #surface {
24
27
  position: fixed;
@@ -34,10 +37,8 @@ const base = css `
34
37
  );
35
38
  padding: var(
36
39
  --modal-padding,
37
- var(--modal-padding-block, var(--eun-space-l, 32px))
40
+ var(--modal-padding-block, var(--eun-space-m, 16px))
38
41
  var(--modal-padding-inline, var(--eun-space-m, 16px))
39
- var(--modal-padding-block, var(--eun-space-m, 16px))
40
- var(--modal-padding-inline, var(--eun-space-l, 32px))
41
42
  );
42
43
  box-sizing: border-box;
43
44
  display: flex;
@@ -112,8 +113,8 @@ const base = css `
112
113
  }
113
114
  #close-button {
114
115
  position: absolute;
115
- top: var(--eun-space-s, 8px);
116
- right: var(--eun-space-s, 8px);
116
+ top: var(--modal-close-offset, var(--eun-space-m, 16px));
117
+ inset-inline-end: var(--modal-close-offset, var(--eun-space-m, 16px));
117
118
  z-index: 10;
118
119
  }
119
120
  #body {
@@ -133,7 +134,17 @@ const base = css `
133
134
  }
134
135
  #heading {
135
136
  margin: 0;
136
- padding-inline-end: var(--eun-space-l, 32px);
137
+ padding-inline-end: max(
138
+ 0px,
139
+ calc(
140
+ var(--modal-close-offset, var(--eun-space-m, 16px)) +
141
+ var(--_closeButtonSize) +
142
+ var(--eun-space-s, 8px) - var(
143
+ --modal-padding-inline,
144
+ var(--eun-space-m, 16px)
145
+ )
146
+ )
147
+ );
137
148
  font-size: var(--eun-font-size-l, 18px);
138
149
  font-weight: var(--eun-font-weight-l, 700);
139
150
  color: var(--eun-text-color, #071621);
@@ -14,6 +14,7 @@ import { popToast, pushToast } from "../../../utils/toast-stack.utils.js";
14
14
  import { resolveIcon } from "../../../utils/severity-icon.utils.js";
15
15
  import { toastStyles } from "./toast.styles.js";
16
16
  import { LocalizableMixin } from "../../../mixins/localizable.mixin.js";
17
+ import { defaultTrueConverter } from "../../../utils/boolean.utils.js";
17
18
  /**
18
19
  * Tag name of the toast component.
19
20
  */
@@ -570,7 +571,7 @@ __decorate([
570
571
  property({ attribute: "rich-text" })
571
572
  ], EunomiaToast.prototype, "richText", void 0);
572
573
  __decorate([
573
- property({ type: Boolean, reflect: true })
574
+ property({ converter: defaultTrueConverter, reflect: true })
574
575
  ], EunomiaToast.prototype, "closeable", void 0);
575
576
  __decorate([
576
577
  property({ attribute: "close-label" })
@@ -579,7 +580,7 @@ __decorate([
579
580
  property({ type: Number })
580
581
  ], EunomiaToast.prototype, "duration", void 0);
581
582
  __decorate([
582
- property({ type: Boolean, reflect: true })
583
+ property({ converter: defaultTrueConverter, reflect: true })
583
584
  ], EunomiaToast.prototype, "open", void 0);
584
585
  __decorate([
585
586
  queryAssignedElements({ slot: "description" })
@@ -49,7 +49,7 @@ const base = css `
49
49
  visibility 0s linear var(--_transitionDuration);
50
50
  }
51
51
 
52
- :host([open]) {
52
+ :host([open]:not([open="false"])) {
53
53
  visibility: visible;
54
54
  opacity: 1;
55
55
  --_baseX: 0px;
@@ -60,7 +60,7 @@ const base = css `
60
60
  visibility 0s linear 0s;
61
61
  }
62
62
 
63
- :host([open][entering]) {
63
+ :host([open]:not([open="false"])[entering]) {
64
64
  visibility: hidden;
65
65
  opacity: 0;
66
66
  --_baseX: var(--_enterX, 0px);
@@ -313,7 +313,7 @@ const base = css `
313
313
  --button-text: var(--_onFilled, #fff);
314
314
  }
315
315
 
316
- :host([closeable]) #toast {
316
+ :host([closeable]:not([closeable="false"])) #toast {
317
317
  padding-right: calc(
318
318
  var(
319
319
  --toast-padding,
@@ -10,6 +10,7 @@ import { CloseEvent } from "../../../events/close.event.js";
10
10
  import { resolveIcon } from "../../../utils/severity-icon.utils.js";
11
11
  import { LocalizableMixin } from "../../../mixins/localizable.mixin.js";
12
12
  import { chipStyles } from "./chip.styles.js";
13
+ import { defaultTrueConverter } from "../../../utils/boolean.utils.js";
13
14
  /**
14
15
  * Tag name of the chip component.
15
16
  */
@@ -363,10 +364,10 @@ __decorate([
363
364
  property({ attribute: "avatar-initials" })
364
365
  ], EunomiaChip.prototype, "avatarInitials", void 0);
365
366
  __decorate([
366
- property({ type: Boolean, reflect: true })
367
+ property({ converter: defaultTrueConverter, reflect: true })
367
368
  ], EunomiaChip.prototype, "rounded", void 0);
368
369
  __decorate([
369
- property({ type: Boolean, reflect: true })
370
+ property({ converter: defaultTrueConverter, reflect: true })
370
371
  ], EunomiaChip.prototype, "removable", void 0);
371
372
  __decorate([
372
373
  property({ type: Boolean, reflect: true })
@@ -65,7 +65,7 @@ const base = css `
65
65
  :host {
66
66
  --_radius: var(--eun-border-radius-s, 5px);
67
67
  }
68
- :host([rounded]) {
68
+ :host([rounded]:not([rounded="false"])) {
69
69
  --_radius: var(--eun-border-radius-xl, 999px);
70
70
  }
71
71
 
@@ -82,8 +82,14 @@ const base = css `
82
82
  --chip-border-* never changes the chip's size. */
83
83
  border: var(--_borderWidth) solid var(--chip-border-color, var(--_bd));
84
84
  border-radius: var(--chip-border-radius, var(--_radius));
85
- padding-inline-start: max(0px, calc(var(--_paddingInline) - var(--_borderWidth)));
86
- padding-inline-end: max(0px, calc(var(--_paddingInline) - var(--_borderWidth)));
85
+ padding-inline-start: max(
86
+ 0px,
87
+ calc(var(--_paddingInline) - var(--_borderWidth))
88
+ );
89
+ padding-inline-end: max(
90
+ 0px,
91
+ calc(var(--_paddingInline) - var(--_borderWidth))
92
+ );
87
93
  font-size: var(--_fontSize);
88
94
  gap: var(--chip-gap, var(--_gap));
89
95
  color: var(--chip-color, var(--_fg));
@@ -14,6 +14,7 @@ import { ImageChangeEvent } from "../../../events/imagechange.event.js";
14
14
  import { imageCarouselStyles } from "./image-carousel.styles.js";
15
15
  import { LocalizableMixin } from "../../../mixins/localizable.mixin.js";
16
16
  import { cssTimeToMs } from "../../../utils/motion.utils.js";
17
+ import { defaultTrueConverter } from "../../../utils/boolean.utils.js";
17
18
  /**
18
19
  * Tag name of the image carousel component.
19
20
  */
@@ -1260,16 +1261,16 @@ __decorate([
1260
1261
  property({ type: Number, attribute: "magnifier-zoom" })
1261
1262
  ], EunomiaImageCarousel.prototype, "magnifierZoom", void 0);
1262
1263
  __decorate([
1263
- property({ type: Boolean, attribute: "show-thumbnails" })
1264
+ property({ converter: defaultTrueConverter, attribute: "show-thumbnails" })
1264
1265
  ], EunomiaImageCarousel.prototype, "showThumbnails", void 0);
1265
1266
  __decorate([
1266
- property({ type: Boolean, attribute: "show-dots" })
1267
+ property({ converter: defaultTrueConverter, attribute: "show-dots" })
1267
1268
  ], EunomiaImageCarousel.prototype, "showDots", void 0);
1268
1269
  __decorate([
1269
- property({ type: Boolean })
1270
+ property({ converter: defaultTrueConverter })
1270
1271
  ], EunomiaImageCarousel.prototype, "lightbox", void 0);
1271
1272
  __decorate([
1272
- property({ type: Boolean, attribute: "lightbox-grid" })
1273
+ property({ converter: defaultTrueConverter, attribute: "lightbox-grid" })
1273
1274
  ], EunomiaImageCarousel.prototype, "lightboxGrid", void 0);
1274
1275
  __decorate([
1275
1276
  property({ type: Boolean })
@@ -614,16 +614,23 @@ export declare class EunomiaTooltip extends EunomiaTooltipMixinBase {
614
614
  */
615
615
  private readGap;
616
616
  /**
617
- * Links the slotted anchor's `aria-describedby` to the panel, so a screen
618
- * reader announces the tooltip's content as a description of the anchor.
619
- * Idempotent — only ever applied once per anchor.
617
+ * Links the anchor's focusable element to the panel, so a screen reader
618
+ * announces the tooltip's content as a description of whatever actually
619
+ * holds focus. Idempotent — only ever applied once per anchor.
620
620
  *
621
- * A plain `id`-string `aria-describedby` reference works correctly here :
622
- * unlike an earlier version of this component (where the panel lived in
623
- * `eun-tooltip`'s own shadow root, a different tree scope than the
624
- * anchor's), the panel is now portaled into the anchor's own tree scope
625
- * (see {@link ensurePortal}), so this is an entirely ordinary same-scope
626
- * ARIA reference.
621
+ * The described element is resolved by `resolveFocusTarget` rather than
622
+ * being the slotted anchor itself : when the anchor is a component
623
+ * (`<eun-link slot="anchor"><a href>…</a></eun-link>`, an `eun-button`
624
+ * with `href`), focus lands on the slotted `<a>` or on a control inside
625
+ * the component's shadow root, and a description set on the host is
626
+ * never announced.
627
+ *
628
+ * When that element shares the panel's tree scope (the anchor itself, or
629
+ * its light DOM descendants, since the panel is portaled into the
630
+ * anchor's own scope, see {@link ensurePortal}), a plain `id`-string
631
+ * `aria-describedby` is enough. A control inside the anchor's shadow root
632
+ * can't reference an id outside it, so it gets an element reference
633
+ * through `ariaDescribedByElements` instead.
627
634
  * @private
628
635
  */
629
636
  private applyAriaDescribedBy;