@aurodesignsystem/auro-library 5.3.2 → 5.4.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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Semantic Release Automated Changelog
2
2
 
3
+ # [5.4.0](https://github.com/AlaskaAirlines/auro-library/compare/v5.3.3...v5.4.0) (2025-08-14)
4
+
5
+
6
+ ### Features
7
+
8
+ * add a11yTransporter util ([817bb3a](https://github.com/AlaskaAirlines/auro-library/commit/817bb3acb9d20e99bc25a89f17db3a8f2ac91ab5))
9
+
10
+ ## [5.3.3](https://github.com/AlaskaAirlines/auro-library/compare/v5.3.2...v5.3.3) (2025-08-08)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * move test related dependencies to devDependencies ([3d877f8](https://github.com/AlaskaAirlines/auro-library/commit/3d877f86c8a98b9ecdb44d83329fe391a8379483))
16
+
3
17
  ## [5.3.2](https://github.com/AlaskaAirlines/auro-library/compare/v5.3.1...v5.3.2) (2025-07-16)
4
18
 
5
19
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aurodesignsystem/auro-library",
3
- "version": "5.3.2",
3
+ "version": "5.4.0",
4
4
  "description": "This repository holds shared scripts, utilities, and workflows utilized across repositories along the Auro Design System.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -14,7 +14,16 @@
14
14
  "bin": {
15
15
  "generateDocs": "./bin/generateDocs.mjs"
16
16
  },
17
+ "dependencies": {
18
+ "@floating-ui/dom": "^1.6.11",
19
+ "handlebars": "^4.7.8",
20
+ "markdown-magic": "^2.6.1"
21
+ },
17
22
  "devDependencies": {
23
+ "sinon": "^20.0.0",
24
+ "npm-run-all": "^4.1.5",
25
+ "@open-wc/testing": "^4.0.0",
26
+ "@aurodesignsystem/auro-cli": "^2.5.0",
18
27
  "@aurodesignsystem/eslint-config": "1.3.4",
19
28
  "@commitlint/cli": "^18.5.0",
20
29
  "@commitlint/config-conventional": "^18.5.0",
@@ -79,14 +88,5 @@
79
88
  },
80
89
  "bugs": {
81
90
  "url": "https://github.com/AlaskaAirlines/auro-library/issues"
82
- },
83
- "dependencies": {
84
- "@aurodesignsystem/auro-cli": "^2.5.0",
85
- "@floating-ui/dom": "^1.6.11",
86
- "@open-wc/testing": "^4.0.0",
87
- "handlebars": "^4.7.8",
88
- "markdown-magic": "^2.6.1",
89
- "npm-run-all": "^4.1.5",
90
- "sinon": "^20.0.0"
91
91
  }
92
92
  }
@@ -0,0 +1,87 @@
1
+ ## Functions
2
+
3
+ <dl>
4
+ <dt><a href="#transportAriaAttributes">transportAriaAttributes</a></dt>
5
+ <dd><p>Transfers all ARIA attributes from the host element to the target element.
6
+ This function allows optional removal of the original attributes and the ability to ignore specific attributes.</p>
7
+ </dd>
8
+ <dt><a href="#transportRoleAttribute">transportRoleAttribute</a></dt>
9
+ <dd><p>Transfers the &#39;role&#39; attribute from the host element to the target element.
10
+ This function can optionally remove the original attribute from the host after transport.</p>
11
+ </dd>
12
+ <dt><a href="#transportTabIndexAttribute">transportTabIndexAttribute</a></dt>
13
+ <dd><p>Transfers the &#39;tabindex&#39; attribute from the host element to the target element.
14
+ This function can optionally remove the original attribute from the host after transport.</p>
15
+ </dd>
16
+ <dt><a href="#transportAllA11yAttributes">transportAllA11yAttributes</a></dt>
17
+ <dd><p>Transfers all accessibility-related attributes (ARIA, role, tabindex) from the host element to the target element.
18
+ This function allows optional removal of the original attributes and the ability to ignore specific attributes.</p>
19
+ </dd>
20
+ </dl>
21
+
22
+ <a name="transportAriaAttributes"></a>
23
+
24
+ ## transportAriaAttributes
25
+ Transfers all ARIA attributes from the host element to the target element.
26
+ This function allows optional removal of the original attributes and the ability to ignore specific attributes.
27
+
28
+ **Kind**: global constant
29
+ **Returns**: <code>function</code> - Function to detach the specific matcher and target pairing.
30
+
31
+ | Param | Type | Default | Description |
32
+ | --- | --- | --- | --- |
33
+ | params | <code>Object</code> | | The parameters object. |
34
+ | params.host | <code>HTMLElement</code> | | The host element to observe. |
35
+ | params.target | <code>HTMLElement</code> | | The target element to receive attributes. |
36
+ | [params.removeOriginal] | <code>boolean</code> | <code>true</code> | Whether to remove original attributes. |
37
+ | [params.ignore] | <code>Array.&lt;String&gt;</code> | | The list of attributes not to transport. |
38
+
39
+ <a name="transportRoleAttribute"></a>
40
+
41
+ ## transportRoleAttribute
42
+ Transfers the 'role' attribute from the host element to the target element.
43
+ This function can optionally remove the original attribute from the host after transport.
44
+
45
+ **Kind**: global constant
46
+ **Returns**: <code>function</code> - Function to detach the specific matcher and target pairing.} param.
47
+
48
+ | Param | Type | Default | Description |
49
+ | --- | --- | --- | --- |
50
+ | params | <code>Object</code> | | The parameters object. |
51
+ | params.host | <code>HTMLElement</code> | | The host element to observe. |
52
+ | params.target | <code>HTMLElement</code> | | The target element to receive attributes. |
53
+ | [params.removeOriginal] | <code>boolean</code> | <code>true</code> | Whether to remove original attributes. |
54
+
55
+ <a name="transportTabIndexAttribute"></a>
56
+
57
+ ## transportTabIndexAttribute
58
+ Transfers the 'tabindex' attribute from the host element to the target element.
59
+ This function can optionally remove the original attribute from the host after transport.
60
+
61
+ **Kind**: global constant
62
+ **Returns**: <code>function</code> - Function to detach the specific matcher and target pairing.} param.
63
+
64
+ | Param | Type | Default | Description |
65
+ | --- | --- | --- | --- |
66
+ | params | <code>Object</code> | | The parameters object. |
67
+ | params.host | <code>HTMLElement</code> | | The host element to observe. |
68
+ | params.target | <code>HTMLElement</code> | | The target element to receive attributes. |
69
+ | [params.removeOriginal] | <code>boolean</code> | <code>true</code> | Whether to remove original attributes. |
70
+
71
+ <a name="transportAllA11yAttributes"></a>
72
+
73
+ ## transportAllA11yAttributes
74
+ Transfers all accessibility-related attributes (ARIA, role, tabindex) from the host element to the target element.
75
+ This function allows optional removal of the original attributes and the ability to ignore specific attributes.
76
+
77
+ **Kind**: global constant
78
+ **Returns**: <code>function</code> - Function to detach the specific matcher and target pairing.} param.
79
+
80
+ | Param | Type | Default | Description |
81
+ | --- | --- | --- | --- |
82
+ | params | <code>Object</code> | | The parameters object. |
83
+ | params.host | <code>HTMLElement</code> | | The host element to observe. |
84
+ | params.target | <code>HTMLElement</code> | | The target element to receive attributes. |
85
+ | [params.removeOriginal] | <code>boolean</code> | <code>true</code> | Whether to remove original attributes. |
86
+ | [params.ignore] | <code>Array.&lt;String&gt;</code> | | The list of attributes not to transport. |
87
+
@@ -0,0 +1,105 @@
1
+ import { transportAttributes } from "./transportAttributes.js";
2
+
3
+ const _matchers = {
4
+ 'aria-': attr => attr.startsWith('aria-'),
5
+ 'role': attr => attr.match(/^role$/),
6
+ 'tabindex': attr => attr.match(/^tabindex$/),
7
+ };
8
+
9
+ /**
10
+ * Transfers all ARIA attributes from the host element to the target element.
11
+ * This function allows optional removal of the original attributes and the ability to ignore specific attributes.
12
+ *
13
+ * @param {Object} params - The parameters object.
14
+ * @param {HTMLElement} params.host - The host element to observe.
15
+ * @param {HTMLElement} params.target - The target element to receive attributes.
16
+ * @param {boolean} [params.removeOriginal=true] - Whether to remove original attributes.
17
+ * @param {Array<String>} [params.ignore] - The list of attributes not to transport.
18
+ *
19
+ * @returns {Function} Function to detach the specific matcher and target pairing.
20
+ */
21
+
22
+ export const transportAriaAttributes = ({ host, target, removeOriginal = true, ignore = undefined }) => {
23
+ return transportAttributes({
24
+ host,
25
+ target,
26
+ match: attr => {
27
+ if (ignore && ignore.includes(attr)) {
28
+ return false;
29
+ }
30
+ return _matchers['aria-'](attr);
31
+ },
32
+ removeOriginal
33
+ });
34
+ };
35
+
36
+ /**
37
+ * Transfers the 'role' attribute from the host element to the target element.
38
+ * This function can optionally remove the original attribute from the host after transport.
39
+ *
40
+ * @param {Object} params - The parameters object.
41
+ * @param {HTMLElement} params.host - The host element to observe.
42
+ * @param {HTMLElement} params.target - The target element to receive attributes.
43
+ * @param {boolean} [params.removeOriginal=true] - Whether to remove original attributes.
44
+ *
45
+ * @returns {Function} Function to detach the specific matcher and target pairing.} param.
46
+ */
47
+ export const transportRoleAttribute = ({ host, target, removeOriginal = true }) => {
48
+ return transportAttributes({
49
+ host,
50
+ target,
51
+ match: _matchers['role'],
52
+ removeOriginal
53
+ });
54
+ };
55
+
56
+ /**
57
+ * Transfers the 'tabindex' attribute from the host element to the target element.
58
+ * This function can optionally remove the original attribute from the host after transport.
59
+ *
60
+ * @param {Object} params - The parameters object.
61
+ * @param {HTMLElement} params.host - The host element to observe.
62
+ * @param {HTMLElement} params.target - The target element to receive attributes.
63
+ * @param {boolean} [params.removeOriginal=true] - Whether to remove original attributes.
64
+ *
65
+ * @returns {Function} Function to detach the specific matcher and target pairing.} param.
66
+ */
67
+ export const transportTabIndexAttribute = ({ host, target, removeOriginal = true }) => {
68
+ return transportAttributes({
69
+ host,
70
+ target,
71
+ match: _matchers['tabindex'],
72
+ removeOriginal
73
+ });
74
+ };
75
+
76
+ /**
77
+ * Transfers all accessibility-related attributes (ARIA, role, tabindex) from the host element to the target element.
78
+ * This function allows optional removal of the original attributes and the ability to ignore specific attributes.
79
+ *
80
+ * @param {Object} params - The parameters object.
81
+ * @param {HTMLElement} params.host - The host element to observe.
82
+ * @param {HTMLElement} params.target - The target element to receive attributes.
83
+ * @param {boolean} [params.removeOriginal=true] - Whether to remove original attributes.
84
+ * @param {Array<String>} [params.ignore] - The list of attributes not to transport.
85
+ *
86
+ * @returns {Function} Function to detach the specific matcher and target pairing.} param.
87
+ */
88
+ export const transportAllA11yAttributes = ({ host, target, removeOriginal = true, ignore = undefined }) => {
89
+ return transportAttributes({
90
+ host,
91
+ target,
92
+ match: attr => {
93
+ if (ignore && ignore.includes(attr)) {
94
+ return false;
95
+ }
96
+ for (const key in _matchers) {
97
+ if (_matchers[key](attr)) {
98
+ return true;
99
+ }
100
+ }
101
+ return false;
102
+ },
103
+ removeOriginal
104
+ });
105
+ }
@@ -0,0 +1,297 @@
1
+ /**
2
+ * Private module-level WeakMap to hold MutationObservers for each host element.
3
+ */
4
+ const _observers = new WeakMap();
5
+
6
+ /**
7
+ * Private module-level WeakMap to hold attribute matchers and targets for each host element.
8
+ * Structure: {
9
+ * host: {
10
+ * matchers: Set<Function>,
11
+ * targets: Map<HTMLElement, Map<Function, {removeOriginal: boolean, currentAttributes: Map<string, string>}>>
12
+ * }
13
+ * }
14
+ */
15
+ const _transportConfig = new WeakMap();
16
+
17
+ /**
18
+ * Transfers all matching attributes from a host element to a target element and observes for future changes.
19
+ *
20
+ * @param {Object} params - The parameters for the function.
21
+ * @param {HTMLElement} params.host - The host element from which attributes will be transported.
22
+ * @param {HTMLElement} params.target - The target element to which attributes will be transported.
23
+ * @param {boolean} [params.removeOriginal=true] - Whether to remove the attributes from the host element.
24
+ * @param {boolean} [params.observe=true] - Whether to attach a MutationObserver to the host element.
25
+ * @returns {Function} A function to detach the observer when no longer needed.
26
+ * @throws {TypeError} If the host or target parameters are not instances of HTMLElement.
27
+ */
28
+ export const transportAttributes = ({ host, target, match, removeOriginal = true }) => {
29
+ // Guard Clause: Ensure host is valid HTMLElement instance
30
+ if (typeof host !== 'object' || !(host instanceof HTMLElement)) {
31
+ throw new TypeError('a11yUtilities.js | transportAttributes | The "host" parameter must be an instance of HTMLElement.');
32
+ }
33
+
34
+ // Guard Clause: Ensure target is valid HTMLElement instance
35
+ if (typeof target !== 'object' || !(target instanceof HTMLElement)) {
36
+ throw new TypeError('a11yUtilities.js | transportAttributes | The "target" parameter must be an instance of HTMLElement.');
37
+ }
38
+
39
+ // Guard Clause: Ensure match is a function
40
+ if (typeof match !== 'function') {
41
+ throw new TypeError('a11yUtilities.js | transportAttributes | The "match" parameter must be a function.');
42
+ }
43
+
44
+ // Guard Clause: Ensure removeOriginal is a boolean
45
+ if (typeof removeOriginal !== 'boolean') {
46
+ throw new TypeError('a11yUtilities.js | transportAttributes | The "removeOriginal" parameter must be a boolean.');
47
+ }
48
+
49
+ // Register this transport and get cleanup function
50
+ return _registerTransport({
51
+ host,
52
+ target,
53
+ matcher: match,
54
+ removeOriginal
55
+ });
56
+ };
57
+
58
+ /**
59
+ * Registers a matcher and target for a host element and attaches an observer if needed.
60
+ *
61
+ * @param {Object} params - The parameters object.
62
+ * @param {HTMLElement} params.host - The host element to observe.
63
+ * @param {HTMLElement} params.target - The target element to receive attributes.
64
+ * @param {Function} params.matcher - Function that determines which attributes to transport.
65
+ * @param {boolean} [params.removeOriginal=true] - Whether to remove original attributes.
66
+ * @returns {Function} Function to detach the specific matcher and target pairing.
67
+ * @private
68
+ */
69
+ const _registerTransport = ({ host, target, matcher, removeOriginal = true }) => {
70
+ // Initialize config for this host if it doesn't exist
71
+ if (!_transportConfig.has(host)) {
72
+ _transportConfig.set(host, {
73
+ matchers: new Set(),
74
+ targets: new Map()
75
+ });
76
+ }
77
+
78
+ const config = _transportConfig.get(host);
79
+
80
+ // Add the matcher to the set of matchers for this host
81
+ config.matchers.add(matcher);
82
+
83
+ // Initialize target entry if it doesn't exist
84
+ if (!config.targets.has(target)) {
85
+ config.targets.set(target, new Map());
86
+ }
87
+
88
+ // Store the matcher with its removeOriginal setting for this target
89
+ config.targets.get(target).set(matcher, {
90
+ removeOriginal,
91
+ currentAttributes: new Map()
92
+ });
93
+
94
+ // Perform initial attribute transport
95
+ _transportAttributes({ host, target, matcher, removeOriginal });
96
+
97
+ // Attach observer
98
+ _attachObserver(host);
99
+
100
+ // Return cleanup function and utility functions
101
+ return {
102
+ cleanup: () => _cleanupTransport(host, target, matcher),
103
+ getObservedAttributes: () => _getObservedAttributes(host, target, matcher),
104
+ getObservedAttribute: (attr) => _getObservedAttribute(host, target, matcher, attr),
105
+ }
106
+ };
107
+
108
+ /**
109
+ * Cleans up resources associated with a specific matcher and target for a host element.
110
+ *
111
+ * @param {HTMLElement} host - The host element.
112
+ * @param {HTMLElement} target - The target element.
113
+ * @param {Function} matcher - The matcher function.
114
+ * @private
115
+ */
116
+ const _cleanupTransport = (host, target, matcher) => {
117
+ const config = _transportConfig.get(host);
118
+ if (!config) return;
119
+
120
+ // Remove this matcher from this target
121
+ const targetMatchers = config.targets.get(target);
122
+ if (targetMatchers) {
123
+ targetMatchers.delete(matcher);
124
+
125
+ // If this target has no more matchers, remove it
126
+ if (targetMatchers.size === 0) {
127
+ config.targets.delete(target);
128
+ }
129
+ }
130
+
131
+ // Check if this matcher is still used by any target
132
+ let matcherStillUsed = false;
133
+ for (const matcherMap of config.targets.values()) {
134
+ if (matcherMap.has(matcher)) {
135
+ matcherStillUsed = true;
136
+ break;
137
+ }
138
+ }
139
+
140
+ // If not used anymore, remove from matchers set
141
+ if (!matcherStillUsed) {
142
+ config.matchers.delete(matcher);
143
+ }
144
+
145
+ // If no more targets or matchers, detach observer
146
+ if (config.targets.size === 0 || config.matchers.size === 0) {
147
+ _detachObserver(host);
148
+ }
149
+ };
150
+
151
+ /**
152
+ * Generic function to transport attributes from a host element to a target element.
153
+ *
154
+ * @param {Object} params - The parameters object.
155
+ * @param {HTMLElement} params.host - The host element from which to transport attributes.
156
+ * @param {HTMLElement} params.target - The target element to which attributes will be transported.
157
+ * @param {Function} params.matcher - Function that takes an attribute name and returns true if it should be transported.
158
+ * @param {boolean} [params.removeOriginal=true] - Whether to remove original attributes from host.
159
+ * @returns {void}
160
+ * @private
161
+ */
162
+ const _transportAttributes = ({ host, target, matcher, removeOriginal = true }) => {
163
+ // Get a list of all matching attributes on the host element and their values
164
+ const matchingAttributes = host.getAttributeNames()
165
+ .filter(attr => matcher(attr))
166
+ .reduce((acc, attr) => {
167
+ acc[attr] = host.getAttribute(attr);
168
+ return acc;
169
+ }, {});
170
+
171
+ // Move matching attributes to the target element, removing them from the host if removeOriginal is true
172
+ Object.entries(matchingAttributes).forEach(([key, value]) => {
173
+ _setObservedAttribute(host, target, matcher, key, value);
174
+ target.setAttribute(key, value);
175
+ if (removeOriginal) {
176
+ host.removeAttribute(key);
177
+ }
178
+ });
179
+ };
180
+
181
+ /**
182
+ * Attaches a MutationObserver to the host element to monitor attribute changes.
183
+ *
184
+ * @param {HTMLElement} host - The element to observe for attribute changes.
185
+ * @returns {MutationObserver} The observer instance.
186
+ * @private
187
+ */
188
+ const _attachObserver = (host) => {
189
+ // If an observer for this host already exists, return it
190
+ if (_observers.has(host)) {
191
+ return _observers.get(host);
192
+ }
193
+
194
+ // Create a new MutationObserver
195
+ const observer = new MutationObserver((mutations) => {
196
+ const config = _transportConfig.get(host);
197
+ if (!config) return;
198
+
199
+ // For each mutation affecting attributes
200
+ mutations
201
+ .filter(mutation => mutation.type === 'attributes')
202
+ .forEach(mutation => {
203
+ const attributeName = mutation.attributeName;
204
+
205
+ // Find matchers that care about this attribute
206
+ for (const matcher of config.matchers) {
207
+ if (matcher(attributeName)) {
208
+ // For each target that uses this matcher
209
+ for (const [target, matcherConfigs] of config.targets.entries()) {
210
+ if (matcherConfigs.has(matcher)) {
211
+ const { removeOriginal } = matcherConfigs.get(matcher);
212
+ _transportAttributes({
213
+ host,
214
+ target,
215
+ matcher,
216
+ removeOriginal
217
+ });
218
+ }
219
+ }
220
+ }
221
+ }
222
+ });
223
+ });
224
+
225
+ // Start observing attribute changes
226
+ observer.observe(host, { attributes: true });
227
+
228
+ // Store the observer
229
+ _observers.set(host, observer);
230
+
231
+ return observer;
232
+ };
233
+
234
+ /**
235
+ * Detaches and cleans up the MutationObserver for a given host element.
236
+ *
237
+ * @param {HTMLElement} host - The element whose observer should be detached.
238
+ * @private
239
+ */
240
+ const _detachObserver = (host) => {
241
+ if (_observers.has(host)) {
242
+ const observer = _observers.get(host);
243
+ observer.disconnect();
244
+ _observers.delete(host);
245
+ }
246
+
247
+ // Clean up the transport config as well
248
+ if (_transportConfig.has(host)) {
249
+ _transportConfig.delete(host);
250
+ }
251
+ };
252
+
253
+ /**
254
+ * Gets the matcher configuration for a specific host, target, and matcher.
255
+ * @param {HTMLElement} host - The host element.
256
+ * @param {HTMLElement} target - The target element.
257
+ * @param {Function} matcher - The matcher function.
258
+ * @returns {Object|undefined} The matcher configuration if found.
259
+ * @private
260
+ */
261
+ const _getMatcherConfig = (host, target, matcher) => {
262
+ const config = _transportConfig.get(host);
263
+ if (!config) return undefined;
264
+
265
+ const targetMatchers = config.targets.get(target);
266
+ if (!targetMatchers) return undefined;
267
+
268
+ return targetMatchers.get(matcher);
269
+ };
270
+
271
+ /**
272
+ * Sets an observed attribute value.
273
+ * @param {HTMLElement} host - The host element.
274
+ * @param {HTMLElement} target - The target element.
275
+ * @param {Function} matcher - The matcher function.
276
+ * @param {string} key - The attribute name.
277
+ * @param {string} value - The attribute value.
278
+ * @private
279
+ */
280
+ const _setObservedAttribute = (host, target, matcher, key, value) => {
281
+ const matcherConfig = _getMatcherConfig(host, target, matcher);
282
+ if (matcherConfig) {
283
+ matcherConfig.currentAttributes.set(key, value);
284
+ }
285
+ };
286
+
287
+ const _getObservedAttribute = (host, target, matcher, attr) => {
288
+ const matcherConfig = _getMatcherConfig(host, target, matcher);
289
+ if (matcherConfig) return matcherConfig.currentAttributes.get(attr);
290
+ return undefined;
291
+ };
292
+
293
+ const _getObservedAttributes = (host, target, matcher) => {
294
+ const matcherConfig = _getMatcherConfig(host, target, matcher);
295
+ if (matcherConfig) return Array.from(matcherConfig.currentAttributes.entries());
296
+ return [];
297
+ };