@vaadin/a11y-base 25.3.0-alpha6 → 25.3.0-dev.1fa5a51482

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/a11y-base",
3
- "version": "25.3.0-alpha6",
3
+ "version": "25.3.0-dev.1fa5a51482",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -32,15 +32,15 @@
32
32
  ],
33
33
  "dependencies": {
34
34
  "@open-wc/dedupe-mixin": "^1.3.0",
35
- "@vaadin/component-base": "25.3.0-alpha6",
35
+ "@vaadin/component-base": "25.3.0-dev.1fa5a51482",
36
36
  "lit": "^3.0.0"
37
37
  },
38
38
  "devDependencies": {
39
- "@vaadin/chai-plugins": "25.3.0-alpha6",
40
- "@vaadin/test-runner-commands": "25.3.0-alpha6",
39
+ "@vaadin/chai-plugins": "25.3.0-dev.1fa5a51482",
40
+ "@vaadin/test-runner-commands": "25.3.0-dev.1fa5a51482",
41
41
  "@vaadin/testing-helpers": "^2.0.0",
42
42
  "sinon": "^22.0.0"
43
43
  },
44
44
  "customElements": "custom-elements.json",
45
- "gitHead": "92c124fb9cff367bc07e734d8e65707facd0bd43"
45
+ "gitHead": "1cd5964b758ffbce3ddb6248a1997f55f8e0ebf6"
46
46
  }
@@ -13,6 +13,9 @@ import { hideOthers } from './aria-hidden.js';
13
13
  * consumer web component. This is done in to ensure the controller only does one thing.
14
14
  */
15
15
  export class AriaModalController {
16
+ /** @type {Function | null} */
17
+ #showOthers = null;
18
+
16
19
  /**
17
20
  * @param {HTMLElement} host
18
21
  */
@@ -42,7 +45,7 @@ export class AriaModalController {
42
45
  */
43
46
  showModal() {
44
47
  const targets = this.callback();
45
- this.__showOthers = hideOthers(targets);
48
+ this.#showOthers = hideOthers(targets);
46
49
  }
47
50
 
48
51
  /**
@@ -50,9 +53,9 @@ export class AriaModalController {
50
53
  * controller hosts on the page activated by using `showModal()` call.
51
54
  */
52
55
  close() {
53
- if (this.__showOthers) {
54
- this.__showOthers();
55
- this.__showOthers = null;
56
+ if (this.#showOthers) {
57
+ this.#showOthers();
58
+ this.#showOthers = null;
56
59
  }
57
60
  }
58
61
  }
@@ -10,9 +10,29 @@ import { removeAriaIDReference, restoreGeneratedAriaIDReference, setAriaIDRefere
10
10
  * either the component itself or slotted `<input>` element.
11
11
  */
12
12
  export class FieldAriaController {
13
+ /** @type {HTMLElement | undefined} */
14
+ #target;
15
+
16
+ /** @type {boolean} */
17
+ #required = false;
18
+
19
+ /** @type {string | null | undefined} */
20
+ #label;
21
+
22
+ /** @type {string | null | undefined} */
23
+ #labelId;
24
+
25
+ /** @type {string | null | undefined} */
26
+ #labelIdFromUser;
27
+
28
+ /** @type {string | null | undefined} */
29
+ #errorId;
30
+
31
+ /** @type {string | null | undefined} */
32
+ #helperId;
33
+
13
34
  constructor(host) {
14
35
  this.host = host;
15
- this.__required = false;
16
36
  }
17
37
 
18
38
  /**
@@ -21,16 +41,16 @@ export class FieldAriaController {
21
41
  * @param {HTMLElement} target
22
42
  */
23
43
  setTarget(target) {
24
- this.__target = target;
25
- this.__setAriaRequiredAttribute(this.__required);
26
- // We need to make sure that value in __labelId is stored
27
- this.__setLabelIdToAriaAttribute(this.__labelId, this.__labelId);
28
- if (this.__labelIdFromUser != null) {
29
- this.__setLabelIdToAriaAttribute(this.__labelIdFromUser, this.__labelIdFromUser, true);
44
+ this.#target = target;
45
+ this.#setAriaRequiredAttribute(this.#required);
46
+ // We need to make sure that value in #labelId is stored
47
+ this.#setLabelIdToAriaAttribute(this.#labelId, this.#labelId);
48
+ if (this.#labelIdFromUser != null) {
49
+ this.#setLabelIdToAriaAttribute(this.#labelIdFromUser, this.#labelIdFromUser, true);
30
50
  }
31
- this.__setErrorIdToAriaAttribute(this.__errorId);
32
- this.__setHelperIdToAriaAttribute(this.__helperId);
33
- this.setAriaLabel(this.__label);
51
+ this.#setErrorIdToAriaAttribute(this.#errorId);
52
+ this.#setHelperIdToAriaAttribute(this.#helperId);
53
+ this.setAriaLabel(this.#label);
34
54
  }
35
55
 
36
56
  /**
@@ -41,8 +61,8 @@ export class FieldAriaController {
41
61
  * @param {boolean} required
42
62
  */
43
63
  setRequired(required) {
44
- this.__setAriaRequiredAttribute(required);
45
- this.__required = required;
64
+ this.#setAriaRequiredAttribute(required);
65
+ this.#required = required;
46
66
  }
47
67
 
48
68
  /**
@@ -53,8 +73,8 @@ export class FieldAriaController {
53
73
  * @param {string | null | undefined} label
54
74
  */
55
75
  setAriaLabel(label) {
56
- this.__setAriaLabelToAttribute(label);
57
- this.__label = label;
76
+ this.#setAriaLabelToAttribute(label);
77
+ this.#label = label;
58
78
  }
59
79
 
60
80
  /**
@@ -66,12 +86,12 @@ export class FieldAriaController {
66
86
  * @param {string | null} labelId
67
87
  */
68
88
  setLabelId(labelId, fromUser = false) {
69
- const oldLabelId = fromUser ? this.__labelIdFromUser : this.__labelId;
70
- this.__setLabelIdToAriaAttribute(labelId, oldLabelId, fromUser);
89
+ const oldLabelId = fromUser ? this.#labelIdFromUser : this.#labelId;
90
+ this.#setLabelIdToAriaAttribute(labelId, oldLabelId, fromUser);
71
91
  if (fromUser) {
72
- this.__labelIdFromUser = labelId;
92
+ this.#labelIdFromUser = labelId;
73
93
  } else {
74
- this.__labelId = labelId;
94
+ this.#labelId = labelId;
75
95
  }
76
96
  }
77
97
 
@@ -85,8 +105,8 @@ export class FieldAriaController {
85
105
  * @param {string | null} errorId
86
106
  */
87
107
  setErrorId(errorId) {
88
- this.__setErrorIdToAriaAttribute(errorId, this.__errorId);
89
- this.__errorId = errorId;
108
+ this.#setErrorIdToAriaAttribute(errorId, this.#errorId);
109
+ this.#errorId = errorId;
90
110
  }
91
111
 
92
112
  /**
@@ -99,24 +119,23 @@ export class FieldAriaController {
99
119
  * @param {string | null} helperId
100
120
  */
101
121
  setHelperId(helperId) {
102
- this.__setHelperIdToAriaAttribute(helperId, this.__helperId);
103
- this.__helperId = helperId;
122
+ this.#setHelperIdToAriaAttribute(helperId, this.#helperId);
123
+ this.#helperId = helperId;
104
124
  }
105
125
 
106
126
  /**
107
127
  * @param {string | null | undefined} label
108
- * @private
109
- * */
110
- __setAriaLabelToAttribute(label) {
111
- if (!this.__target) {
128
+ */
129
+ #setAriaLabelToAttribute(label) {
130
+ if (!this.#target) {
112
131
  return;
113
132
  }
114
133
  if (label) {
115
- removeAriaIDReference(this.__target, 'aria-labelledby');
116
- this.__target.setAttribute('aria-label', label);
117
- } else if (this.__label) {
118
- restoreGeneratedAriaIDReference(this.__target, 'aria-labelledby');
119
- this.__target.removeAttribute('aria-label');
134
+ removeAriaIDReference(this.#target, 'aria-labelledby');
135
+ this.#target.setAttribute('aria-label', label);
136
+ } else if (this.#label) {
137
+ restoreGeneratedAriaIDReference(this.#target, 'aria-labelledby');
138
+ this.#target.removeAttribute('aria-label');
120
139
  }
121
140
  }
122
141
 
@@ -124,48 +143,44 @@ export class FieldAriaController {
124
143
  * @param {string | null | undefined} labelId
125
144
  * @param {string | null | undefined} oldLabelId
126
145
  * @param {boolean | null | undefined} fromUser
127
- * @private
128
146
  */
129
- __setLabelIdToAriaAttribute(labelId, oldLabelId, fromUser) {
130
- setAriaIDReference(this.__target, 'aria-labelledby', { newId: labelId, oldId: oldLabelId, fromUser });
147
+ #setLabelIdToAriaAttribute(labelId, oldLabelId, fromUser) {
148
+ setAriaIDReference(this.#target, 'aria-labelledby', { newId: labelId, oldId: oldLabelId, fromUser });
131
149
  }
132
150
 
133
151
  /**
134
152
  * @param {string | null | undefined} errorId
135
153
  * @param {string | null | undefined} oldErrorId
136
- * @private
137
154
  */
138
- __setErrorIdToAriaAttribute(errorId, oldErrorId) {
139
- setAriaIDReference(this.__target, 'aria-describedby', { newId: errorId, oldId: oldErrorId, fromUser: false });
155
+ #setErrorIdToAriaAttribute(errorId, oldErrorId) {
156
+ setAriaIDReference(this.#target, 'aria-describedby', { newId: errorId, oldId: oldErrorId, fromUser: false });
140
157
  }
141
158
 
142
159
  /**
143
160
  * @param {string | null | undefined} helperId
144
161
  * @param {string | null | undefined} oldHelperId
145
- * @private
146
162
  */
147
- __setHelperIdToAriaAttribute(helperId, oldHelperId) {
148
- setAriaIDReference(this.__target, 'aria-describedby', { newId: helperId, oldId: oldHelperId, fromUser: false });
163
+ #setHelperIdToAriaAttribute(helperId, oldHelperId) {
164
+ setAriaIDReference(this.#target, 'aria-describedby', { newId: helperId, oldId: oldHelperId, fromUser: false });
149
165
  }
150
166
 
151
167
  /**
152
168
  * @param {boolean} required
153
- * @private
154
169
  */
155
- __setAriaRequiredAttribute(required) {
156
- if (!this.__target) {
170
+ #setAriaRequiredAttribute(required) {
171
+ if (!this.#target) {
157
172
  return;
158
173
  }
159
174
 
160
- if (['input', 'textarea'].includes(this.__target.localName)) {
175
+ if (['input', 'textarea'].includes(this.#target.localName)) {
161
176
  // Native <input> or <textarea>, required is enough
162
177
  return;
163
178
  }
164
179
 
165
180
  if (required) {
166
- this.__target.setAttribute('aria-required', 'true');
181
+ this.#target.setAttribute('aria-required', 'true');
167
182
  } else {
168
- this.__target.removeAttribute('aria-required');
183
+ this.#target.removeAttribute('aria-required');
169
184
  }
170
185
  }
171
186
  }
@@ -20,6 +20,11 @@ export class FocusTrapController implements ReactiveController {
20
20
  */
21
21
  host: HTMLElement;
22
22
 
23
+ /**
24
+ * A node for trapping focus in.
25
+ */
26
+ trapNode: HTMLElement | null;
27
+
23
28
  constructor(node: HTMLElement);
24
29
 
25
30
  hostConnected(): void;
@@ -17,8 +17,8 @@ const instances = [];
17
17
  export function getActiveTrappingNode(element) {
18
18
  // Iterate backwards since instances are ordered outer-to-inner (push/pop)
19
19
  for (let i = instances.length - 1; i >= 0; i--) {
20
- if (instances[i].__trapNode?.contains(element)) {
21
- return instances[i].__trapNode;
20
+ if (instances[i].trapNode?.contains(element)) {
21
+ return instances[i].trapNode;
22
22
  }
23
23
  }
24
24
  return null;
@@ -28,6 +28,13 @@ export function getActiveTrappingNode(element) {
28
28
  * A controller for trapping focus within a DOM node.
29
29
  */
30
30
  export class FocusTrapController {
31
+ /**
32
+ * A node for trapping focus in.
33
+ *
34
+ * @type {HTMLElement | null}
35
+ */
36
+ trapNode = null;
37
+
31
38
  /**
32
39
  * @param {HTMLElement} host
33
40
  */
@@ -38,45 +45,33 @@ export class FocusTrapController {
38
45
  * @type {HTMLElement}
39
46
  */
40
47
  this.host = host;
41
-
42
- /**
43
- * A node for trapping focus in.
44
- *
45
- * @type {HTMLElement | null}
46
- * @private
47
- */
48
- this.__trapNode = null;
49
-
50
- this.__onKeyDown = this.__onKeyDown.bind(this);
51
48
  }
52
49
 
53
50
  /**
54
51
  * An array of tab-ordered focusable elements inside the trap node.
55
52
  *
56
53
  * @return {HTMLElement[]}
57
- * @private
58
54
  */
59
- get __focusableElements() {
60
- return getTabbableElements(this.__trapNode);
55
+ get #focusableElements() {
56
+ return getTabbableElements(this.trapNode);
61
57
  }
62
58
 
63
59
  /**
64
60
  * The index of the element inside the trap node that currently has focus.
65
61
  *
66
62
  * @return {HTMLElement | undefined}
67
- * @private
68
63
  */
69
- get __focusedElementIndex() {
70
- const focusableElements = this.__focusableElements;
64
+ get #focusedElementIndex() {
65
+ const focusableElements = this.#focusableElements;
71
66
  return focusableElements.indexOf(focusableElements.filter(isElementFocused).pop());
72
67
  }
73
68
 
74
69
  hostConnected() {
75
- document.addEventListener('keydown', this.__onKeyDown);
70
+ document.addEventListener('keydown', this.#onKeyDown);
76
71
  }
77
72
 
78
73
  hostDisconnected() {
79
- document.removeEventListener('keydown', this.__onKeyDown);
74
+ document.removeEventListener('keydown', this.#onKeyDown);
80
75
  }
81
76
 
82
77
  /**
@@ -94,17 +89,17 @@ export class FocusTrapController {
94
89
  * @param {HTMLElement} trapNode
95
90
  */
96
91
  trapFocus(trapNode) {
97
- this.__trapNode = trapNode;
92
+ this.trapNode = trapNode;
98
93
 
99
- if (this.__focusableElements.length === 0) {
100
- this.__trapNode = null;
94
+ if (this.#focusableElements.length === 0) {
95
+ this.trapNode = null;
101
96
  throw new Error('The trap node should have at least one focusable descendant or be focusable itself.');
102
97
  }
103
98
 
104
99
  instances.push(this);
105
100
 
106
- if (this.__focusedElementIndex === -1) {
107
- this.__focusableElements[0].focus({ focusVisible: isKeyboardActive() });
101
+ if (this.#focusedElementIndex === -1) {
102
+ this.#focusableElements[0].focus({ focusVisible: isKeyboardActive() });
108
103
  }
109
104
  }
110
105
 
@@ -113,7 +108,7 @@ export class FocusTrapController {
113
108
  * so that it becomes possible to tab outside the trap node.
114
109
  */
115
110
  releaseFocus() {
116
- this.__trapNode = null;
111
+ this.trapNode = null;
117
112
 
118
113
  instances.pop();
119
114
  }
@@ -127,10 +122,9 @@ export class FocusTrapController {
127
122
  * When no prev element to focus, the method moves focus to the last focusable element.
128
123
  *
129
124
  * @param {KeyboardEvent} event
130
- * @private
131
125
  */
132
- __onKeyDown(event) {
133
- if (!this.__trapNode) {
126
+ #onKeyDown = (event) => {
127
+ if (!this.trapNode) {
134
128
  return;
135
129
  }
136
130
 
@@ -148,9 +142,9 @@ export class FocusTrapController {
148
142
  event.preventDefault();
149
143
 
150
144
  const backward = event.shiftKey;
151
- this.__focusNextElement(backward);
145
+ this.#focusNextElement(backward);
152
146
  }
153
- }
147
+ };
154
148
 
155
149
  /**
156
150
  * - Moves focus to the next focusable element if `backward === false`.
@@ -161,12 +155,11 @@ export class FocusTrapController {
161
155
  * If no focusable elements, the method returns immediately.
162
156
  *
163
157
  * @param {boolean} backward
164
- * @private
165
158
  */
166
- __focusNextElement(backward = false) {
167
- const focusableElements = this.__focusableElements;
159
+ #focusNextElement(backward = false) {
160
+ const focusableElements = this.#focusableElements;
168
161
  const step = backward ? -1 : 1;
169
- const currentIndex = this.__focusedElementIndex;
162
+ const currentIndex = this.#focusedElementIndex;
170
163
  const nextIndex = (focusableElements.length + currentIndex + step) % focusableElements.length;
171
164
  const element = focusableElements[nextIndex];
172
165
  element.focus({ focusVisible: true });