@nectary/components 5.42.2 → 5.42.3

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/bundle.js CHANGED
@@ -3485,6 +3485,12 @@ class Pop extends NectaryElement {
3485
3485
  targetStyleValue: null,
3486
3486
  transformedAncestor: null
3487
3487
  };
3488
+ static #dialogA11yAttrs = [
3489
+ "aria-label",
3490
+ "aria-labelledby",
3491
+ "aria-describedby",
3492
+ "aria-description"
3493
+ ];
3488
3494
  constructor() {
3489
3495
  super();
3490
3496
  const shadowRoot = this.attachShadow();
@@ -3515,7 +3521,7 @@ class Pop extends NectaryElement {
3515
3521
  const { signal } = this.#controller;
3516
3522
  this.#keydownContext.listen(signal);
3517
3523
  this.#visibilityContext.listen(signal);
3518
- this.setAttribute("role", "dialog");
3524
+ this.#syncDialogA11yAttrs();
3519
3525
  this.#$dialog.addEventListener("cancel", this.#onCancel, { signal });
3520
3526
  this.#$dialog.addEventListener("mousedown", this.#onBackdropMouseDown, { signal });
3521
3527
  this.addEventListener("-close", this.#onCloseReactHandler, { signal });
@@ -3536,7 +3542,12 @@ class Pop extends NectaryElement {
3536
3542
  static get observedAttributes() {
3537
3543
  return [
3538
3544
  "orientation",
3539
- "open"
3545
+ "open",
3546
+ "modal",
3547
+ "aria-label",
3548
+ "aria-labelledby",
3549
+ "aria-describedby",
3550
+ "aria-description"
3540
3551
  ];
3541
3552
  }
3542
3553
  get allowScroll() {
@@ -3606,8 +3617,43 @@ class Pop extends NectaryElement {
3606
3617
  }
3607
3618
  break;
3608
3619
  }
3620
+ case "modal": {
3621
+ if (this.#$dialog.open) {
3622
+ this.#syncDialogSemantics(this.#shouldUseModalSemantics());
3623
+ }
3624
+ break;
3625
+ }
3626
+ case "aria-label":
3627
+ case "aria-labelledby":
3628
+ case "aria-describedby":
3629
+ case "aria-description": {
3630
+ this.#syncDialogA11yAttrs();
3631
+ break;
3632
+ }
3609
3633
  }
3610
3634
  }
3635
+ #syncDialogA11yAttrs() {
3636
+ Pop.#dialogA11yAttrs.forEach((attrName) => {
3637
+ const attrVal = this.getAttribute(attrName);
3638
+ if (attrVal === null) {
3639
+ this.#$dialog.removeAttribute(attrName);
3640
+ } else {
3641
+ this.#$dialog.setAttribute(attrName, attrVal);
3642
+ }
3643
+ });
3644
+ }
3645
+ #syncDialogSemantics(useDialogSemantics) {
3646
+ if (useDialogSemantics) {
3647
+ this.setAttribute("role", "dialog");
3648
+ this.#$dialog.setAttribute("aria-modal", "true");
3649
+ return;
3650
+ }
3651
+ this.removeAttribute("role");
3652
+ this.#$dialog.removeAttribute("aria-modal");
3653
+ }
3654
+ #shouldUseModalSemantics(transformedAncestor = this.#openSession.transformedAncestor) {
3655
+ return this.modal && transformedAncestor === null;
3656
+ }
3611
3657
  #getTargetRect() {
3612
3658
  let item = getFirstSlotElement(this.#$targetSlot, true);
3613
3659
  if (item === null && this.#$dialog.open) {
@@ -3682,7 +3728,7 @@ class Pop extends NectaryElement {
3682
3728
  }
3683
3729
  const transformedAncestor = getTransformedAncestor(this);
3684
3730
  const effectiveAllowScroll = this.allowScroll || transformedAncestor != null;
3685
- const shouldUseModal = this.modal && transformedAncestor == null;
3731
+ const shouldUseModal = this.#shouldUseModalSemantics(transformedAncestor);
3686
3732
  const openAsModal = shouldUseModal || !effectiveAllowScroll;
3687
3733
  this.#openSession = {
3688
3734
  effectiveAllowScroll,
@@ -3690,6 +3736,8 @@ class Pop extends NectaryElement {
3690
3736
  targetStyleValue: null,
3691
3737
  transformedAncestor
3692
3738
  };
3739
+ this.#syncDialogA11yAttrs();
3740
+ this.#syncDialogSemantics(shouldUseModal);
3693
3741
  this.#$targetSlot.addEventListener("blur", this.#stopEventPropagation, true);
3694
3742
  this.#$focus.setAttribute("tabindex", "-1");
3695
3743
  this.#$focus.style.display = "block";
@@ -3800,6 +3848,7 @@ class Pop extends NectaryElement {
3800
3848
  targetStyleValue: null,
3801
3849
  transformedAncestor: null
3802
3850
  };
3851
+ this.#syncDialogSemantics(false);
3803
3852
  }
3804
3853
  #onResize = () => {
3805
3854
  this.#resizeThrottle.fn();
@@ -4166,6 +4215,7 @@ class Tooltip extends NectaryElement {
4166
4215
  updateAttribute(this.#$pop, "orientation", getPopOrientation$1(this.orientation));
4167
4216
  updateBooleanAttribute(this.#$pop, "hide-outside-viewport", !this.showOutsideViewport);
4168
4217
  updateBooleanAttribute(this.#$pop, "disable-focus-restore", true);
4218
+ this.#updatePopAriaLabel();
4169
4219
  this.#updateText();
4170
4220
  }
4171
4221
  disconnectedCallback() {
@@ -4211,6 +4261,7 @@ class Tooltip extends NectaryElement {
4211
4261
  switch (name) {
4212
4262
  case "text": {
4213
4263
  this.#updateText();
4264
+ this.#updatePopAriaLabel();
4214
4265
  break;
4215
4266
  }
4216
4267
  case "orientation": {
@@ -4233,7 +4284,11 @@ class Tooltip extends NectaryElement {
4233
4284
  }
4234
4285
  case "aria-label":
4235
4286
  case "aria-description": {
4236
- updateAttribute(this.#$pop, name, newVal);
4287
+ if (name === "aria-label") {
4288
+ this.#updatePopAriaLabel();
4289
+ } else {
4290
+ updateAttribute(this.#$pop, name, newVal);
4291
+ }
4237
4292
  break;
4238
4293
  }
4239
4294
  case "show-outside-viewport": {
@@ -4809,6 +4864,13 @@ class Tooltip extends NectaryElement {
4809
4864
  this.#subscribeMouseEnterEvent();
4810
4865
  }
4811
4866
  }
4867
+ #updatePopAriaLabel() {
4868
+ const rawAriaLabel = getAttribute(this, "aria-label");
4869
+ const explicitAriaLabel = rawAriaLabel !== null && rawAriaLabel.trim().length > 0 ? rawAriaLabel.trim() : null;
4870
+ const fallbackAriaLabel = this.text ?? "";
4871
+ const ariaLabel = explicitAriaLabel ?? (fallbackAriaLabel.length === 0 ? null : fallbackAriaLabel);
4872
+ updateAttribute(this.#$pop, "aria-label", ariaLabel);
4873
+ }
4812
4874
  #subscribeMouseEnterEvent() {
4813
4875
  if (!this.isDomConnected || this.#isSubscribed) {
4814
4876
  return;
@@ -9582,7 +9644,7 @@ class HelpTooltip extends NectaryElement {
9582
9644
  this.#controller = null;
9583
9645
  }
9584
9646
  static get observedAttributes() {
9585
- return ["aria-label", "text", "width", "orientation"];
9647
+ return ["aria-label", "text", "orientation"];
9586
9648
  }
9587
9649
  attributeChangedCallback(name, _, newVal) {
9588
9650
  updateAttribute(this.#$tooltip, name, newVal);
@@ -9593,12 +9655,6 @@ class HelpTooltip extends NectaryElement {
9593
9655
  set text(value) {
9594
9656
  updateAttribute(this, "text", value);
9595
9657
  }
9596
- get width() {
9597
- return getIntegerAttribute(this, "width");
9598
- }
9599
- set width(value) {
9600
- updateIntegerAttribute(this, "width", value);
9601
- }
9602
9658
  get orientation() {
9603
9659
  return getAttribute(this, "orientation", "top");
9604
9660
  }
@@ -11,8 +11,6 @@ export declare class HelpTooltip extends NectaryElement {
11
11
  attributeChangedCallback(name: string, _: string | null, newVal: string | null): void;
12
12
  get text(): string;
13
13
  set text(value: string);
14
- get width(): number | undefined;
15
- set width(value: number | undefined);
16
14
  get orientation(): string;
17
15
  set orientation(value: string);
18
16
  get footprintRect(): import("../types").TRect;
@@ -1,6 +1,6 @@
1
1
  import "../tooltip/index.js";
2
2
  import "../icon/index.js";
3
- import { updateAttribute, getAttribute, getIntegerAttribute, updateIntegerAttribute } from "../utils/dom.js";
3
+ import { updateAttribute, getAttribute } from "../utils/dom.js";
4
4
  import { defineCustomElement, NectaryElement } from "../utils/element.js";
5
5
  import { getReactEventHandler } from "../utils/get-react-event-handler.js";
6
6
  const templateHTML = '<style>:host{display:contents}#icon{--sinch-global-size-icon:18px}</style><sinch-tooltip type="fast"><sinch-icon icons-version="2" name="circle-question" id="icon"></sinch-icon></sinch-tooltip>';
@@ -30,7 +30,7 @@ class HelpTooltip extends NectaryElement {
30
30
  this.#controller = null;
31
31
  }
32
32
  static get observedAttributes() {
33
- return ["aria-label", "text", "width", "orientation"];
33
+ return ["aria-label", "text", "orientation"];
34
34
  }
35
35
  attributeChangedCallback(name, _, newVal) {
36
36
  updateAttribute(this.#$tooltip, name, newVal);
@@ -41,12 +41,6 @@ class HelpTooltip extends NectaryElement {
41
41
  set text(value) {
42
42
  updateAttribute(this, "text", value);
43
43
  }
44
- get width() {
45
- return getIntegerAttribute(this, "width");
46
- }
47
- set width(value) {
48
- updateIntegerAttribute(this, "width", value);
49
- }
50
44
  get orientation() {
51
45
  return getAttribute(this, "orientation", "top");
52
46
  }
@@ -1,6 +1,15 @@
1
- import type { TSinchTooltipProps } from '../tooltip/types';
2
- import type { NectaryComponentReactByType, NectaryComponentVanillaByType, NectaryComponentReact, NectaryComponentVanilla } from '../types';
3
- export type TSinchHelpTooltipProps = TSinchTooltipProps;
1
+ import type { TSinchTooltipOrientation } from '../tooltip/types';
2
+ import type { NectaryComponentReactByType, NectaryComponentVanillaByType, NectaryComponentReact, NectaryComponentVanilla, TRect } from '../types';
3
+ export type TSinchHelpTooltipProps = {
4
+ /** Accessible name for the tooltip content */
5
+ 'aria-label'?: string;
6
+ /** Text */
7
+ text: string;
8
+ /** Orientation, where it *points to* from origin */
9
+ orientation?: TSinchTooltipOrientation;
10
+ readonly footprintRect?: TRect;
11
+ readonly tooltipRect?: TRect;
12
+ };
4
13
  export type TSinchHelpTooltipStyle = {
5
14
  '--sinch-global-size-icon'?: string;
6
15
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nectary/components",
3
- "version": "5.42.2",
3
+ "version": "5.42.3",
4
4
  "files": [
5
5
  "**/*/*.css",
6
6
  "**/*/*.json",
package/pop/index.js CHANGED
@@ -35,6 +35,12 @@ class Pop extends NectaryElement {
35
35
  targetStyleValue: null,
36
36
  transformedAncestor: null
37
37
  };
38
+ static #dialogA11yAttrs = [
39
+ "aria-label",
40
+ "aria-labelledby",
41
+ "aria-describedby",
42
+ "aria-description"
43
+ ];
38
44
  constructor() {
39
45
  super();
40
46
  const shadowRoot = this.attachShadow();
@@ -65,7 +71,7 @@ class Pop extends NectaryElement {
65
71
  const { signal } = this.#controller;
66
72
  this.#keydownContext.listen(signal);
67
73
  this.#visibilityContext.listen(signal);
68
- this.setAttribute("role", "dialog");
74
+ this.#syncDialogA11yAttrs();
69
75
  this.#$dialog.addEventListener("cancel", this.#onCancel, { signal });
70
76
  this.#$dialog.addEventListener("mousedown", this.#onBackdropMouseDown, { signal });
71
77
  this.addEventListener("-close", this.#onCloseReactHandler, { signal });
@@ -86,7 +92,12 @@ class Pop extends NectaryElement {
86
92
  static get observedAttributes() {
87
93
  return [
88
94
  "orientation",
89
- "open"
95
+ "open",
96
+ "modal",
97
+ "aria-label",
98
+ "aria-labelledby",
99
+ "aria-describedby",
100
+ "aria-description"
90
101
  ];
91
102
  }
92
103
  get allowScroll() {
@@ -156,8 +167,43 @@ class Pop extends NectaryElement {
156
167
  }
157
168
  break;
158
169
  }
170
+ case "modal": {
171
+ if (this.#$dialog.open) {
172
+ this.#syncDialogSemantics(this.#shouldUseModalSemantics());
173
+ }
174
+ break;
175
+ }
176
+ case "aria-label":
177
+ case "aria-labelledby":
178
+ case "aria-describedby":
179
+ case "aria-description": {
180
+ this.#syncDialogA11yAttrs();
181
+ break;
182
+ }
159
183
  }
160
184
  }
185
+ #syncDialogA11yAttrs() {
186
+ Pop.#dialogA11yAttrs.forEach((attrName) => {
187
+ const attrVal = this.getAttribute(attrName);
188
+ if (attrVal === null) {
189
+ this.#$dialog.removeAttribute(attrName);
190
+ } else {
191
+ this.#$dialog.setAttribute(attrName, attrVal);
192
+ }
193
+ });
194
+ }
195
+ #syncDialogSemantics(useDialogSemantics) {
196
+ if (useDialogSemantics) {
197
+ this.setAttribute("role", "dialog");
198
+ this.#$dialog.setAttribute("aria-modal", "true");
199
+ return;
200
+ }
201
+ this.removeAttribute("role");
202
+ this.#$dialog.removeAttribute("aria-modal");
203
+ }
204
+ #shouldUseModalSemantics(transformedAncestor = this.#openSession.transformedAncestor) {
205
+ return this.modal && transformedAncestor === null;
206
+ }
161
207
  #getTargetRect() {
162
208
  let item = getFirstSlotElement(this.#$targetSlot, true);
163
209
  if (item === null && this.#$dialog.open) {
@@ -232,7 +278,7 @@ class Pop extends NectaryElement {
232
278
  }
233
279
  const transformedAncestor = getTransformedAncestor(this);
234
280
  const effectiveAllowScroll = this.allowScroll || transformedAncestor != null;
235
- const shouldUseModal = this.modal && transformedAncestor == null;
281
+ const shouldUseModal = this.#shouldUseModalSemantics(transformedAncestor);
236
282
  const openAsModal = shouldUseModal || !effectiveAllowScroll;
237
283
  this.#openSession = {
238
284
  effectiveAllowScroll,
@@ -240,6 +286,8 @@ class Pop extends NectaryElement {
240
286
  targetStyleValue: null,
241
287
  transformedAncestor
242
288
  };
289
+ this.#syncDialogA11yAttrs();
290
+ this.#syncDialogSemantics(shouldUseModal);
243
291
  this.#$targetSlot.addEventListener("blur", this.#stopEventPropagation, true);
244
292
  this.#$focus.setAttribute("tabindex", "-1");
245
293
  this.#$focus.style.display = "block";
@@ -350,6 +398,7 @@ class Pop extends NectaryElement {
350
398
  targetStyleValue: null,
351
399
  transformedAncestor: null
352
400
  };
401
+ this.#syncDialogSemantics(false);
353
402
  }
354
403
  #onResize = () => {
355
404
  this.#resizeThrottle.fn();
package/tooltip/index.js CHANGED
@@ -94,6 +94,7 @@ class Tooltip extends NectaryElement {
94
94
  updateAttribute(this.#$pop, "orientation", getPopOrientation(this.orientation));
95
95
  updateBooleanAttribute(this.#$pop, "hide-outside-viewport", !this.showOutsideViewport);
96
96
  updateBooleanAttribute(this.#$pop, "disable-focus-restore", true);
97
+ this.#updatePopAriaLabel();
97
98
  this.#updateText();
98
99
  }
99
100
  disconnectedCallback() {
@@ -139,6 +140,7 @@ class Tooltip extends NectaryElement {
139
140
  switch (name) {
140
141
  case "text": {
141
142
  this.#updateText();
143
+ this.#updatePopAriaLabel();
142
144
  break;
143
145
  }
144
146
  case "orientation": {
@@ -161,7 +163,11 @@ class Tooltip extends NectaryElement {
161
163
  }
162
164
  case "aria-label":
163
165
  case "aria-description": {
164
- updateAttribute(this.#$pop, name, newVal);
166
+ if (name === "aria-label") {
167
+ this.#updatePopAriaLabel();
168
+ } else {
169
+ updateAttribute(this.#$pop, name, newVal);
170
+ }
165
171
  break;
166
172
  }
167
173
  case "show-outside-viewport": {
@@ -737,6 +743,13 @@ class Tooltip extends NectaryElement {
737
743
  this.#subscribeMouseEnterEvent();
738
744
  }
739
745
  }
746
+ #updatePopAriaLabel() {
747
+ const rawAriaLabel = getAttribute(this, "aria-label");
748
+ const explicitAriaLabel = rawAriaLabel !== null && rawAriaLabel.trim().length > 0 ? rawAriaLabel.trim() : null;
749
+ const fallbackAriaLabel = this.text ?? "";
750
+ const ariaLabel = explicitAriaLabel ?? (fallbackAriaLabel.length === 0 ? null : fallbackAriaLabel);
751
+ updateAttribute(this.#$pop, "aria-label", ariaLabel);
752
+ }
740
753
  #subscribeMouseEnterEvent() {
741
754
  if (!this.isDomConnected || this.#isSubscribed) {
742
755
  return;
@@ -20,6 +20,10 @@ export type TSinchTooltipProps = {
20
20
  * to true can have unexpected behavior in dialogs
21
21
  */
22
22
  'allow-scroll'?: boolean;
23
+ /** Overrides the accessible name of the tooltip popup. Falls back to `text` when absent or empty. */
24
+ 'aria-label'?: string;
25
+ /** Sets the aria-description on the tooltip popup */
26
+ 'aria-description'?: string;
23
27
  };
24
28
  export type TSinchTooltipEvents = {
25
29
  /** Show event handler */