accented 0.0.1-dev.4 → 1.0.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.
Files changed (217) hide show
  1. package/NOTICE +14 -0
  2. package/README.md +71 -0
  3. package/dist/accented.d.ts +28 -7
  4. package/dist/accented.d.ts.map +1 -1
  5. package/dist/accented.js +107 -42
  6. package/dist/accented.js.map +1 -1
  7. package/dist/common/tokens.d.ts +7 -0
  8. package/dist/common/tokens.d.ts.map +1 -0
  9. package/dist/common/tokens.js +8 -0
  10. package/dist/common/tokens.js.map +1 -0
  11. package/dist/constants.d.ts +4 -0
  12. package/dist/constants.d.ts.map +1 -0
  13. package/dist/constants.js +4 -0
  14. package/dist/constants.js.map +1 -0
  15. package/dist/dom-updater.d.ts +1 -6
  16. package/dist/dom-updater.d.ts.map +1 -1
  17. package/dist/dom-updater.js +136 -20
  18. package/dist/dom-updater.js.map +1 -1
  19. package/dist/elements/accented-dialog.d.ts +359 -0
  20. package/dist/elements/accented-dialog.d.ts.map +1 -0
  21. package/dist/elements/accented-dialog.js +377 -0
  22. package/dist/elements/accented-dialog.js.map +1 -0
  23. package/dist/elements/accented-trigger.d.ts +364 -0
  24. package/dist/elements/accented-trigger.d.ts.map +1 -0
  25. package/dist/elements/accented-trigger.js +214 -0
  26. package/dist/elements/accented-trigger.js.map +1 -0
  27. package/dist/fullscreen-listener.d.ts +2 -0
  28. package/dist/fullscreen-listener.d.ts.map +1 -0
  29. package/dist/fullscreen-listener.js +17 -0
  30. package/dist/fullscreen-listener.js.map +1 -0
  31. package/dist/intersection-observer.d.ts +5 -0
  32. package/dist/intersection-observer.d.ts.map +1 -0
  33. package/dist/intersection-observer.js +34 -0
  34. package/dist/intersection-observer.js.map +1 -0
  35. package/dist/log-and-rethrow.d.ts +2 -0
  36. package/dist/log-and-rethrow.d.ts.map +1 -0
  37. package/dist/log-and-rethrow.js +6 -0
  38. package/dist/log-and-rethrow.js.map +1 -0
  39. package/dist/logger.d.ts +2 -0
  40. package/dist/logger.d.ts.map +1 -0
  41. package/dist/logger.js +28 -0
  42. package/dist/logger.js.map +1 -0
  43. package/dist/register-elements.d.ts +2 -0
  44. package/dist/register-elements.d.ts.map +1 -0
  45. package/dist/register-elements.js +20 -0
  46. package/dist/register-elements.js.map +1 -0
  47. package/dist/resize-listener.d.ts +2 -0
  48. package/dist/resize-listener.d.ts.map +1 -0
  49. package/dist/resize-listener.js +17 -0
  50. package/dist/resize-listener.js.map +1 -0
  51. package/dist/scanner.d.ts +3 -0
  52. package/dist/scanner.d.ts.map +1 -0
  53. package/dist/scanner.js +153 -0
  54. package/dist/scanner.js.map +1 -0
  55. package/dist/scroll-listeners.d.ts +2 -0
  56. package/dist/scroll-listeners.d.ts.map +1 -0
  57. package/dist/scroll-listeners.js +37 -0
  58. package/dist/scroll-listeners.js.map +1 -0
  59. package/dist/state.d.ts +7 -0
  60. package/dist/state.d.ts.map +1 -0
  61. package/dist/state.js +16 -0
  62. package/dist/state.js.map +1 -0
  63. package/dist/task-queue.d.ts +5 -6
  64. package/dist/task-queue.d.ts.map +1 -1
  65. package/dist/task-queue.js +30 -25
  66. package/dist/task-queue.js.map +1 -1
  67. package/dist/types.d.ts +227 -0
  68. package/dist/types.d.ts.map +1 -0
  69. package/dist/types.js +2 -0
  70. package/dist/types.js.map +1 -0
  71. package/dist/utils/are-elements-with-issues-equal.d.ts +3 -0
  72. package/dist/utils/are-elements-with-issues-equal.d.ts.map +1 -0
  73. package/dist/utils/are-elements-with-issues-equal.js +5 -0
  74. package/dist/utils/are-elements-with-issues-equal.js.map +1 -0
  75. package/dist/utils/are-issue-sets-equal.d.ts +3 -0
  76. package/dist/utils/are-issue-sets-equal.d.ts.map +1 -0
  77. package/dist/utils/are-issue-sets-equal.js +6 -0
  78. package/dist/utils/are-issue-sets-equal.js.map +1 -0
  79. package/dist/utils/containing-blocks.d.ts +3 -0
  80. package/dist/utils/containing-blocks.d.ts.map +1 -0
  81. package/dist/utils/containing-blocks.js +46 -0
  82. package/dist/utils/containing-blocks.js.map +1 -0
  83. package/dist/utils/contains.d.ts +2 -0
  84. package/dist/utils/contains.d.ts.map +1 -0
  85. package/dist/utils/contains.js +19 -0
  86. package/dist/utils/contains.js.map +1 -0
  87. package/dist/utils/deduplicate-nodes.d.ts +2 -0
  88. package/dist/utils/deduplicate-nodes.d.ts.map +1 -0
  89. package/dist/utils/deduplicate-nodes.js +4 -0
  90. package/dist/utils/deduplicate-nodes.js.map +1 -0
  91. package/dist/utils/deep-merge.d.ts +4 -0
  92. package/dist/utils/deep-merge.d.ts.map +1 -0
  93. package/dist/utils/deep-merge.js +21 -0
  94. package/dist/utils/deep-merge.js.map +1 -0
  95. package/dist/utils/dom-helpers.d.ts +9 -0
  96. package/dist/utils/dom-helpers.d.ts.map +1 -0
  97. package/dist/utils/dom-helpers.js +34 -0
  98. package/dist/utils/dom-helpers.js.map +1 -0
  99. package/dist/utils/ensure-non-empty.d.ts +2 -0
  100. package/dist/utils/ensure-non-empty.d.ts.map +1 -0
  101. package/dist/utils/ensure-non-empty.js +7 -0
  102. package/dist/utils/ensure-non-empty.js.map +1 -0
  103. package/dist/utils/get-element-html.d.ts +2 -0
  104. package/dist/utils/get-element-html.d.ts.map +1 -0
  105. package/dist/utils/get-element-html.js +16 -0
  106. package/dist/utils/get-element-html.js.map +1 -0
  107. package/dist/utils/get-element-position.d.ts +11 -0
  108. package/dist/utils/get-element-position.d.ts.map +1 -0
  109. package/dist/utils/get-element-position.js +70 -0
  110. package/dist/utils/get-element-position.js.map +1 -0
  111. package/dist/utils/get-parent.d.ts +2 -0
  112. package/dist/utils/get-parent.d.ts.map +1 -0
  113. package/dist/utils/get-parent.js +12 -0
  114. package/dist/utils/get-parent.js.map +1 -0
  115. package/dist/utils/get-scan-context.d.ts +3 -0
  116. package/dist/utils/get-scan-context.d.ts.map +1 -0
  117. package/dist/utils/get-scan-context.js +28 -0
  118. package/dist/utils/get-scan-context.js.map +1 -0
  119. package/dist/utils/get-scrollable-ancestors.d.ts +2 -0
  120. package/dist/utils/get-scrollable-ancestors.d.ts.map +1 -0
  121. package/dist/utils/get-scrollable-ancestors.js +19 -0
  122. package/dist/utils/get-scrollable-ancestors.js.map +1 -0
  123. package/dist/utils/is-node-in-scan-context.d.ts +3 -0
  124. package/dist/utils/is-node-in-scan-context.d.ts.map +1 -0
  125. package/dist/utils/is-node-in-scan-context.js +26 -0
  126. package/dist/utils/is-node-in-scan-context.js.map +1 -0
  127. package/dist/utils/is-non-empty.d.ts +2 -0
  128. package/dist/utils/is-non-empty.d.ts.map +1 -0
  129. package/dist/utils/is-non-empty.js +4 -0
  130. package/dist/utils/is-non-empty.js.map +1 -0
  131. package/dist/utils/normalize-context.d.ts +3 -0
  132. package/dist/utils/normalize-context.d.ts.map +1 -0
  133. package/dist/utils/normalize-context.js +59 -0
  134. package/dist/utils/normalize-context.js.map +1 -0
  135. package/dist/utils/recalculate-positions.d.ts +2 -0
  136. package/dist/utils/recalculate-positions.d.ts.map +1 -0
  137. package/dist/utils/recalculate-positions.js +27 -0
  138. package/dist/utils/recalculate-positions.js.map +1 -0
  139. package/dist/utils/recalculate-scrollable-ancestors.d.ts +2 -0
  140. package/dist/utils/recalculate-scrollable-ancestors.d.ts.map +1 -0
  141. package/dist/utils/recalculate-scrollable-ancestors.js +13 -0
  142. package/dist/utils/recalculate-scrollable-ancestors.js.map +1 -0
  143. package/dist/utils/shadow-dom-aware-mutation-observer.d.ts +10 -0
  144. package/dist/utils/shadow-dom-aware-mutation-observer.d.ts.map +1 -0
  145. package/dist/utils/shadow-dom-aware-mutation-observer.js +61 -0
  146. package/dist/utils/shadow-dom-aware-mutation-observer.js.map +1 -0
  147. package/dist/utils/supports-anchor-positioning.d.ts +6 -0
  148. package/dist/utils/supports-anchor-positioning.d.ts.map +1 -0
  149. package/dist/utils/supports-anchor-positioning.js +4 -0
  150. package/dist/utils/supports-anchor-positioning.js.map +1 -0
  151. package/dist/utils/transform-violations.d.ts +4 -0
  152. package/dist/utils/transform-violations.d.ts.map +1 -0
  153. package/dist/utils/transform-violations.js +61 -0
  154. package/dist/utils/transform-violations.js.map +1 -0
  155. package/dist/utils/update-elements-with-issues.d.ts +13 -0
  156. package/dist/utils/update-elements-with-issues.d.ts.map +1 -0
  157. package/dist/utils/update-elements-with-issues.js +96 -0
  158. package/dist/utils/update-elements-with-issues.js.map +1 -0
  159. package/dist/validate-options.d.ts +3 -0
  160. package/dist/validate-options.d.ts.map +1 -0
  161. package/dist/validate-options.js +129 -0
  162. package/dist/validate-options.js.map +1 -0
  163. package/package.json +21 -8
  164. package/src/accented.test.ts +24 -0
  165. package/src/accented.ts +130 -0
  166. package/src/common/tokens.ts +10 -0
  167. package/src/constants.ts +3 -0
  168. package/src/dom-updater.ts +165 -0
  169. package/src/elements/accented-dialog.ts +419 -0
  170. package/src/elements/accented-trigger.ts +251 -0
  171. package/src/fullscreen-listener.ts +21 -0
  172. package/src/intersection-observer.ts +39 -0
  173. package/src/log-and-rethrow.ts +8 -0
  174. package/src/logger.ts +36 -0
  175. package/src/register-elements.ts +21 -0
  176. package/src/resize-listener.ts +21 -0
  177. package/src/scanner.ts +195 -0
  178. package/src/scroll-listeners.ts +45 -0
  179. package/src/state.ts +35 -0
  180. package/src/task-queue.test.ts +136 -0
  181. package/src/task-queue.ts +61 -0
  182. package/src/types.ts +258 -0
  183. package/src/utils/are-elements-with-issues-equal.ts +11 -0
  184. package/src/utils/are-issue-sets-equal.test.ts +53 -0
  185. package/src/utils/are-issue-sets-equal.ts +12 -0
  186. package/src/utils/containing-blocks.ts +60 -0
  187. package/src/utils/contains.test.ts +54 -0
  188. package/src/utils/contains.ts +19 -0
  189. package/src/utils/deduplicate-nodes.ts +3 -0
  190. package/src/utils/deep-merge.test.ts +41 -0
  191. package/src/utils/deep-merge.ts +24 -0
  192. package/src/utils/dom-helpers.ts +42 -0
  193. package/src/utils/ensure-non-empty.ts +6 -0
  194. package/src/utils/get-element-html.ts +15 -0
  195. package/src/utils/get-element-position.ts +89 -0
  196. package/src/utils/get-parent.ts +14 -0
  197. package/src/utils/get-scan-context.test.ts +85 -0
  198. package/src/utils/get-scan-context.ts +36 -0
  199. package/src/utils/get-scrollable-ancestors.ts +22 -0
  200. package/src/utils/is-node-in-scan-context.test.ts +70 -0
  201. package/src/utils/is-node-in-scan-context.ts +29 -0
  202. package/src/utils/is-non-empty.ts +3 -0
  203. package/src/utils/normalize-context.test.ts +105 -0
  204. package/src/utils/normalize-context.ts +65 -0
  205. package/src/utils/recalculate-positions.ts +27 -0
  206. package/src/utils/recalculate-scrollable-ancestors.ts +13 -0
  207. package/src/utils/shadow-dom-aware-mutation-observer.ts +75 -0
  208. package/src/utils/supports-anchor-positioning.ts +7 -0
  209. package/src/utils/transform-violations.test.ts +128 -0
  210. package/src/utils/transform-violations.ts +74 -0
  211. package/src/utils/update-elements-with-issues.test.ts +371 -0
  212. package/src/utils/update-elements-with-issues.ts +144 -0
  213. package/src/validate-options.ts +184 -0
  214. package/dist/utils/issuesToElements.d.ts +0 -3
  215. package/dist/utils/issuesToElements.d.ts.map +0 -1
  216. package/dist/utils/issuesToElements.js +0 -16
  217. package/dist/utils/issuesToElements.js.map +0 -1
@@ -0,0 +1,144 @@
1
+ import type { Signal } from '@preact/signals-core';
2
+ import { batch, signal } from '@preact/signals-core';
3
+ import type { AxeResults } from 'axe-core';
4
+ import type { AccentedDialog } from '../elements/accented-dialog.ts';
5
+ import type { AccentedTrigger } from '../elements/accented-trigger.ts';
6
+ import type { ExtendedElementWithIssues, ScanContext } from '../types.ts';
7
+ import { areElementsWithIssuesEqual } from './are-elements-with-issues-equal.js';
8
+ import { areIssueSetsEqual } from './are-issue-sets-equal.js';
9
+ import { isSvgElement } from './dom-helpers.js';
10
+ import { getElementPosition } from './get-element-position.js';
11
+ import { getParent } from './get-parent.js';
12
+ import { getScrollableAncestors } from './get-scrollable-ancestors.js';
13
+ import { isNodeInScanContext } from './is-node-in-scan-context.js';
14
+ import { supportsAnchorPositioning } from './supports-anchor-positioning.js';
15
+ import { transformViolations } from './transform-violations.js';
16
+
17
+ function shouldSkipRender(element: Element): boolean {
18
+ // Skip rendering if the element is inside an SVG:
19
+ // https://github.com/pomerantsev/accented/issues/62
20
+ const parent = getParent(element);
21
+ const isInsideSvg = Boolean(parent && isSvgElement(parent));
22
+
23
+ // Some issues, such as meta-viewport, are on <head> descendants,
24
+ // but since <head> is never rendered, we don't want to output anything
25
+ // for those in the DOM.
26
+ // We're not anticipating the use of shadow DOM in <head>,
27
+ // so the use of .closest() should be fine.
28
+ const isInsideHead = element.closest('head') !== null;
29
+
30
+ return isInsideSvg || isInsideHead;
31
+ }
32
+
33
+ let count = 0;
34
+
35
+ export function updateElementsWithIssues({
36
+ extendedElementsWithIssues,
37
+ scanContext,
38
+ violations,
39
+ win,
40
+ name,
41
+ }: {
42
+ extendedElementsWithIssues: Signal<Array<ExtendedElementWithIssues>>;
43
+ scanContext: ScanContext;
44
+ violations: typeof AxeResults.violations;
45
+ win: Window & { CSS: typeof CSS };
46
+ name: string;
47
+ }) {
48
+ const updatedElementsWithIssues = transformViolations(violations, name);
49
+
50
+ batch(() => {
51
+ for (const updatedElementWithIssues of updatedElementsWithIssues) {
52
+ const existingElementIndex = extendedElementsWithIssues.value.findIndex(
53
+ (extendedElementWithIssues) =>
54
+ areElementsWithIssuesEqual(extendedElementWithIssues, updatedElementWithIssues),
55
+ );
56
+ if (
57
+ existingElementIndex > -1 &&
58
+ extendedElementsWithIssues.value[existingElementIndex] &&
59
+ !areIssueSetsEqual(
60
+ extendedElementsWithIssues.value[existingElementIndex].issues.value,
61
+ updatedElementWithIssues.issues,
62
+ )
63
+ ) {
64
+ extendedElementsWithIssues.value[existingElementIndex].issues.value =
65
+ updatedElementWithIssues.issues;
66
+ }
67
+ }
68
+
69
+ const addedElementsWithIssues = updatedElementsWithIssues.filter((updatedElementWithIssues) => {
70
+ return !extendedElementsWithIssues.value.some((extendedElementWithIssues) =>
71
+ areElementsWithIssuesEqual(extendedElementWithIssues, updatedElementWithIssues),
72
+ );
73
+ });
74
+
75
+ // Only consider an element to be removed in two cases:
76
+ // 1. It has been removed from the DOM.
77
+ // 2. It is within the scan context, but not among updatedElementsWithIssues.
78
+ const removedElementsWithIssues = extendedElementsWithIssues.value.filter(
79
+ (extendedElementWithIssues) => {
80
+ const isConnected = extendedElementWithIssues.element.isConnected;
81
+ const hasNoMoreIssues =
82
+ isNodeInScanContext(extendedElementWithIssues.element, scanContext) &&
83
+ !updatedElementsWithIssues.some((updatedElementWithIssues) =>
84
+ areElementsWithIssuesEqual(updatedElementWithIssues, extendedElementWithIssues),
85
+ );
86
+ return !isConnected || hasNoMoreIssues;
87
+ },
88
+ );
89
+
90
+ if (addedElementsWithIssues.length > 0 || removedElementsWithIssues.length > 0) {
91
+ extendedElementsWithIssues.value = [...extendedElementsWithIssues.value]
92
+ .filter((extendedElementWithIssues) => {
93
+ return !removedElementsWithIssues.some((removedElementWithIssues) =>
94
+ areElementsWithIssuesEqual(removedElementWithIssues, extendedElementWithIssues),
95
+ );
96
+ })
97
+ .concat(
98
+ addedElementsWithIssues
99
+ .filter((addedElementWithIssues) => addedElementWithIssues.element.isConnected)
100
+ .map((addedElementWithIssues) => {
101
+ const id = count++;
102
+ const trigger = win.document.createElement(`${name}-trigger`) as AccentedTrigger;
103
+ const elementZIndex = Number.parseInt(
104
+ win.getComputedStyle(addedElementWithIssues.element).zIndex,
105
+ 10,
106
+ );
107
+ if (!Number.isNaN(elementZIndex)) {
108
+ trigger.style.setProperty('z-index', (elementZIndex + 1).toString(), 'important');
109
+ }
110
+ trigger.style.setProperty('position-anchor', `--${name}-anchor-${id}`, 'important');
111
+ trigger.dataset.id = id.toString();
112
+ const accentedDialog = win.document.createElement(`${name}-dialog`) as AccentedDialog;
113
+ trigger.dialog = accentedDialog;
114
+ const position = getElementPosition(addedElementWithIssues.element, win);
115
+ trigger.position = signal(position);
116
+ trigger.visible = signal(true);
117
+ trigger.element = addedElementWithIssues.element;
118
+ const scrollableAncestors = supportsAnchorPositioning(win)
119
+ ? new Set<HTMLElement>()
120
+ : getScrollableAncestors(addedElementWithIssues.element, win);
121
+ const issues = signal(addedElementWithIssues.issues);
122
+ accentedDialog.issues = issues;
123
+ accentedDialog.element = addedElementWithIssues.element;
124
+ return {
125
+ id,
126
+ element: addedElementWithIssues.element,
127
+ skipRender: shouldSkipRender(addedElementWithIssues.element),
128
+ rootNode: addedElementWithIssues.rootNode,
129
+ visible: trigger.visible,
130
+ position: trigger.position,
131
+ scrollableAncestors: signal(scrollableAncestors),
132
+ anchorNameValue:
133
+ addedElementWithIssues.element.style.getPropertyValue('anchor-name') ||
134
+ win
135
+ .getComputedStyle(addedElementWithIssues.element)
136
+ .getPropertyValue('anchor-name'),
137
+ trigger,
138
+ issues,
139
+ };
140
+ }),
141
+ );
142
+ }
143
+ });
144
+ }
@@ -0,0 +1,184 @@
1
+ import { allowedAxeOptions } from './types.js';
2
+ import type {
3
+ AccentedOptions,
4
+ Context,
5
+ ContextObject,
6
+ ContextProp,
7
+ Selector,
8
+ SelectorList,
9
+ } from './types.ts';
10
+ import { isNode, isNodeList } from './utils/dom-helpers.js';
11
+
12
+ function isSelector(contextFragment: Context): contextFragment is Selector {
13
+ return (
14
+ typeof contextFragment === 'string' ||
15
+ isNode(contextFragment) ||
16
+ 'fromShadowDom' in contextFragment
17
+ );
18
+ }
19
+
20
+ function validateSelector(selector: Selector) {
21
+ if (typeof selector === 'string') {
22
+ return;
23
+ }
24
+ if (isNode(selector)) {
25
+ return;
26
+ }
27
+ if ('fromShadowDom' in selector) {
28
+ if (
29
+ !Array.isArray(selector.fromShadowDom) ||
30
+ selector.fromShadowDom.length < 2 ||
31
+ !selector.fromShadowDom.every((item) => typeof item === 'string')
32
+ ) {
33
+ throw new TypeError(
34
+ `Accented: invalid argument. \`fromShadowDom\` must be an array of strings with at least 2 elements. It’s currently set to ${selector.fromShadowDom}.`,
35
+ );
36
+ }
37
+ return;
38
+ }
39
+ const neverSelector: never = selector;
40
+ throw new TypeError(
41
+ `Accented: invalid argument. The selector must be one of: string, Node, or an object with a \`fromShadowDom\` property. It’s currently set to ${neverSelector}.`,
42
+ );
43
+ }
44
+
45
+ function isSelectorList(contextFragment: Context): contextFragment is SelectorList {
46
+ return (
47
+ (typeof contextFragment === 'object' && isNodeList(contextFragment)) ||
48
+ (Array.isArray(contextFragment) && contextFragment.every((item) => isSelector(item)))
49
+ );
50
+ }
51
+
52
+ function validateSelectorList(selectorList: SelectorList) {
53
+ if (isNodeList(selectorList)) {
54
+ return;
55
+ }
56
+ if (Array.isArray(selectorList)) {
57
+ for (const selector of selectorList) {
58
+ validateSelector(selector);
59
+ }
60
+ } else {
61
+ const neverSelectorList: never = selectorList;
62
+ throw new TypeError(
63
+ `Accented: invalid argument. The selector list must either be a NodeList or an array. It’s currently set to ${neverSelectorList}.`,
64
+ );
65
+ }
66
+ }
67
+
68
+ function isContextProp(contextFragment: Context): contextFragment is ContextProp {
69
+ return isSelector(contextFragment) || isSelectorList(contextFragment);
70
+ }
71
+
72
+ function validateContextProp(context: Selector | SelectorList) {
73
+ if (isSelector(context)) {
74
+ validateSelector(context);
75
+ } else if (isSelectorList(context)) {
76
+ validateSelectorList(context);
77
+ } else {
78
+ const neverContext: never = context;
79
+ throw new TypeError(
80
+ `Accented: invalid argument. The context property must either be a selector or a selector list. It’s currently set to ${neverContext}.`,
81
+ );
82
+ }
83
+ }
84
+
85
+ function isContextObject(contextFragment: Context): contextFragment is ContextObject {
86
+ return (
87
+ typeof contextFragment === 'object' &&
88
+ contextFragment !== null &&
89
+ ('include' in contextFragment || 'exclude' in contextFragment)
90
+ );
91
+ }
92
+
93
+ function validateContextObject(contextObject: ContextObject) {
94
+ if ('include' in contextObject && contextObject.include !== undefined) {
95
+ validateContextProp(contextObject.include);
96
+ }
97
+ if ('exclude' in contextObject && contextObject.exclude !== undefined) {
98
+ validateContextProp(contextObject.exclude);
99
+ }
100
+ }
101
+
102
+ function validateContext(context: Context) {
103
+ if (isContextProp(context)) {
104
+ validateContextProp(context);
105
+ } else if (isContextObject(context)) {
106
+ validateContextObject(context);
107
+ } else {
108
+ const neverContext: never = context;
109
+ throw new TypeError(
110
+ `Accented: invalid context argument. It’s currently set to ${neverContext}.`,
111
+ );
112
+ }
113
+ }
114
+
115
+ // The space of valid CSS and HTML names is wider than this,
116
+ // but with Unicode it gets complicated quickly, so I'm sticking to only allowing
117
+ // lowercase alphanumeric names that possibly contain dashes that start with a letter.
118
+ const nameRegex = /^[a-z]([a-z0-9]|-)+$/;
119
+
120
+ export function validateOptions(options: AccentedOptions) {
121
+ if (typeof options !== 'object' || options === null) {
122
+ throw new TypeError(
123
+ `Accented: invalid argument. The options parameter must be an object if provided. It’s currently set to ${options}.`,
124
+ );
125
+ }
126
+ if (options.throttle !== undefined) {
127
+ if (typeof options.throttle !== 'object' || options.throttle === null) {
128
+ throw new TypeError(
129
+ `Accented: invalid argument. \`throttle\` option must be an object if provided. It’s currently set to ${options.throttle}.`,
130
+ );
131
+ }
132
+ if (
133
+ options.throttle.wait !== undefined &&
134
+ (typeof options.throttle.wait !== 'number' || options.throttle.wait < 0)
135
+ ) {
136
+ throw new TypeError(
137
+ `Accented: invalid argument. \`throttle.wait\` option must be a non-negative number if provided. It’s currently set to ${options.throttle.wait}.`,
138
+ );
139
+ }
140
+ }
141
+ if (options.output !== undefined) {
142
+ if (typeof options.output !== 'object' || options.output === null) {
143
+ throw new TypeError(
144
+ `Accented: invalid argument. \`output\` option must be an object if provided. It’s currently set to ${options.output}.`,
145
+ );
146
+ }
147
+ if (options.output.console !== undefined && typeof options.output.console !== 'boolean') {
148
+ console.warn(
149
+ `Accented: invalid argument. \`output.console\` option is expected to be a boolean. It’s currently set to ${options.output.console}.`,
150
+ );
151
+ }
152
+ }
153
+ if (options.callback !== undefined && typeof options.callback !== 'function') {
154
+ throw new TypeError(
155
+ `Accented: invalid argument. \`callback\` option must be a function if provided. It’s currently set to ${options.callback}.`,
156
+ );
157
+ }
158
+ if (
159
+ options.name !== undefined &&
160
+ (typeof options.name !== 'string' || !options.name.match(nameRegex))
161
+ ) {
162
+ throw new TypeError(
163
+ `Accented: invalid argument. \`name\` option must be a string that starts with a lowercase letter and only contains lowercase alphanumeric characters and dashes. It’s currently set to ${options.name}.`,
164
+ );
165
+ }
166
+ if (options.axeOptions !== undefined) {
167
+ if (typeof options.axeOptions !== 'object' || options.axeOptions === null) {
168
+ throw new TypeError(
169
+ `Accented: invalid argument. \`axeOptions\` option must be an object if provided. It’s currently set to ${options.axeOptions}.`,
170
+ );
171
+ }
172
+ const unsupportedKeys = Object.keys(options.axeOptions).filter(
173
+ (key) => !(allowedAxeOptions as unknown as Array<string>).includes(key),
174
+ );
175
+ if (unsupportedKeys.length > 0) {
176
+ throw new TypeError(
177
+ `Accented: invalid argument. \`axeOptions\` contains the following unsupported keys: ${unsupportedKeys.join(', ')}. Valid options are: ${allowedAxeOptions.join(', ')}.`,
178
+ );
179
+ }
180
+ }
181
+ if (options.context !== undefined) {
182
+ validateContext(options.context);
183
+ }
184
+ }
@@ -1,3 +0,0 @@
1
- import type { AxeResults } from 'axe-core';
2
- export default function issuesToElements(issues: typeof AxeResults.violations): Element[];
3
- //# sourceMappingURL=issuesToElements.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"issuesToElements.d.ts","sourceRoot":"","sources":["../../src/utils/issuesToElements.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAE3C,MAAM,CAAC,OAAO,UAAU,gBAAgB,CAAC,MAAM,EAAE,OAAO,UAAU,CAAC,UAAU,aAgB5E"}
@@ -1,16 +0,0 @@
1
- export default function issuesToElements(issues) {
2
- const elements = new Set();
3
- for (const issue of issues) {
4
- for (const node of issue.nodes) {
5
- // TODO: how to make this easier / more reliable?
6
- if (typeof node.target[0] === 'string') {
7
- const element = document.querySelector(node.target[0]);
8
- if (element) {
9
- elements.add(element);
10
- }
11
- }
12
- }
13
- }
14
- return [...elements];
15
- }
16
- //# sourceMappingURL=issuesToElements.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"issuesToElements.js","sourceRoot":"","sources":["../../src/utils/issuesToElements.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,OAAO,UAAU,gBAAgB,CAAC,MAAoC;IAC3E,MAAM,QAAQ,GAAiB,IAAI,GAAG,EAAE,CAAC;IAEzC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YAC/B,iDAAiD;YACjD,IAAI,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC;gBACvC,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;gBACvD,IAAI,OAAO,EAAE,CAAC;oBACZ,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBACxB,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,QAAQ,CAAC,CAAC;AACvB,CAAC"}