accented 0.0.0-20250124142030 → 0.0.0-20250303013509

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 (129) hide show
  1. package/README.md +55 -3
  2. package/dist/accented.d.ts +3 -1
  3. package/dist/accented.d.ts.map +1 -1
  4. package/dist/accented.js +69 -50
  5. package/dist/accented.js.map +1 -1
  6. package/dist/constants.d.ts +3 -0
  7. package/dist/constants.d.ts.map +1 -0
  8. package/dist/constants.js +3 -0
  9. package/dist/constants.js.map +1 -0
  10. package/dist/dom-updater.d.ts +1 -1
  11. package/dist/dom-updater.d.ts.map +1 -1
  12. package/dist/dom-updater.js +26 -19
  13. package/dist/dom-updater.js.map +1 -1
  14. package/dist/elements/{accented-container.d.ts → accented-dialog.d.ts} +10 -4
  15. package/dist/elements/accented-dialog.d.ts.map +1 -0
  16. package/dist/elements/accented-dialog.js +371 -0
  17. package/dist/elements/accented-dialog.js.map +1 -0
  18. package/dist/elements/accented-trigger.d.ts +361 -0
  19. package/dist/elements/accented-trigger.d.ts.map +1 -0
  20. package/dist/elements/accented-trigger.js +188 -0
  21. package/dist/elements/accented-trigger.js.map +1 -0
  22. package/dist/intersection-observer.d.ts +5 -0
  23. package/dist/intersection-observer.d.ts.map +1 -0
  24. package/dist/intersection-observer.js +28 -0
  25. package/dist/intersection-observer.js.map +1 -0
  26. package/dist/log-and-rethrow.d.ts +2 -0
  27. package/dist/log-and-rethrow.d.ts.map +1 -0
  28. package/dist/log-and-rethrow.js +7 -0
  29. package/dist/log-and-rethrow.js.map +1 -0
  30. package/dist/logger.d.ts.map +1 -1
  31. package/dist/logger.js +10 -5
  32. package/dist/logger.js.map +1 -1
  33. package/dist/register-elements.d.ts +2 -0
  34. package/dist/register-elements.d.ts.map +1 -0
  35. package/dist/register-elements.js +21 -0
  36. package/dist/register-elements.js.map +1 -0
  37. package/dist/resize-listener.d.ts +2 -0
  38. package/dist/resize-listener.d.ts.map +1 -0
  39. package/dist/resize-listener.js +18 -0
  40. package/dist/resize-listener.js.map +1 -0
  41. package/dist/scanner.d.ts +2 -2
  42. package/dist/scanner.d.ts.map +1 -1
  43. package/dist/scanner.js +97 -33
  44. package/dist/scanner.js.map +1 -1
  45. package/dist/scroll-listeners.d.ts +2 -0
  46. package/dist/scroll-listeners.d.ts.map +1 -0
  47. package/dist/scroll-listeners.js +38 -0
  48. package/dist/scroll-listeners.js.map +1 -0
  49. package/dist/state.d.ts +1 -0
  50. package/dist/state.d.ts.map +1 -1
  51. package/dist/state.js +6 -0
  52. package/dist/state.js.map +1 -1
  53. package/dist/types.d.ts +71 -18
  54. package/dist/types.d.ts.map +1 -1
  55. package/dist/types.js +1 -0
  56. package/dist/types.js.map +1 -1
  57. package/dist/utils/deep-merge.js +1 -1
  58. package/dist/utils/deep-merge.js.map +1 -1
  59. package/dist/utils/get-element-html.d.ts +2 -0
  60. package/dist/utils/get-element-html.d.ts.map +1 -0
  61. package/dist/utils/get-element-html.js +14 -0
  62. package/dist/utils/get-element-html.js.map +1 -0
  63. package/dist/utils/get-element-position.d.ts +3 -0
  64. package/dist/utils/get-element-position.d.ts.map +1 -0
  65. package/dist/utils/get-element-position.js +58 -0
  66. package/dist/utils/get-element-position.js.map +1 -0
  67. package/dist/utils/get-scrollable-ancestors.d.ts +2 -0
  68. package/dist/utils/get-scrollable-ancestors.d.ts.map +1 -0
  69. package/dist/utils/get-scrollable-ancestors.js +15 -0
  70. package/dist/utils/get-scrollable-ancestors.js.map +1 -0
  71. package/dist/utils/is-html-element.d.ts +2 -0
  72. package/dist/utils/is-html-element.d.ts.map +1 -0
  73. package/dist/utils/is-html-element.js +7 -0
  74. package/dist/utils/is-html-element.js.map +1 -0
  75. package/dist/utils/recalculate-positions.d.ts +2 -0
  76. package/dist/utils/recalculate-positions.d.ts.map +1 -0
  77. package/dist/utils/recalculate-positions.js +27 -0
  78. package/dist/utils/recalculate-positions.js.map +1 -0
  79. package/dist/utils/recalculate-scrollable-ancestors.d.ts +2 -0
  80. package/dist/utils/recalculate-scrollable-ancestors.d.ts.map +1 -0
  81. package/dist/utils/recalculate-scrollable-ancestors.js +13 -0
  82. package/dist/utils/recalculate-scrollable-ancestors.js.map +1 -0
  83. package/dist/utils/supports-anchor-positioning.d.ts +6 -0
  84. package/dist/utils/supports-anchor-positioning.d.ts.map +1 -0
  85. package/dist/utils/supports-anchor-positioning.js +4 -0
  86. package/dist/utils/supports-anchor-positioning.js.map +1 -0
  87. package/dist/utils/transform-violations.d.ts.map +1 -1
  88. package/dist/utils/transform-violations.js +9 -0
  89. package/dist/utils/transform-violations.js.map +1 -1
  90. package/dist/utils/update-elements-with-issues.d.ts +3 -1
  91. package/dist/utils/update-elements-with-issues.d.ts.map +1 -1
  92. package/dist/utils/update-elements-with-issues.js +25 -7
  93. package/dist/utils/update-elements-with-issues.js.map +1 -1
  94. package/dist/validate-options.d.ts +3 -0
  95. package/dist/validate-options.d.ts.map +1 -0
  96. package/dist/validate-options.js +42 -0
  97. package/dist/validate-options.js.map +1 -0
  98. package/package.json +2 -1
  99. package/src/accented.ts +78 -58
  100. package/src/constants.ts +2 -0
  101. package/src/dom-updater.ts +26 -18
  102. package/src/elements/accented-dialog.ts +394 -0
  103. package/src/elements/accented-trigger.ts +214 -0
  104. package/src/intersection-observer.ts +28 -0
  105. package/src/log-and-rethrow.ts +9 -0
  106. package/src/logger.ts +11 -6
  107. package/src/register-elements.ts +21 -0
  108. package/src/resize-listener.ts +17 -0
  109. package/src/scanner.ts +108 -37
  110. package/src/scroll-listeners.ts +37 -0
  111. package/src/state.ts +12 -0
  112. package/src/types.ts +78 -19
  113. package/src/utils/deep-merge.test.ts +7 -0
  114. package/src/utils/deep-merge.ts +1 -1
  115. package/src/utils/get-element-html.ts +13 -0
  116. package/src/utils/get-element-position.ts +59 -0
  117. package/src/utils/get-scrollable-ancestors.ts +14 -0
  118. package/src/utils/is-html-element.ts +6 -0
  119. package/src/utils/recalculate-positions.ts +27 -0
  120. package/src/utils/recalculate-scrollable-ancestors.ts +13 -0
  121. package/src/utils/supports-anchor-positioning.ts +7 -0
  122. package/src/utils/transform-violations.ts +12 -1
  123. package/src/utils/update-elements-with-issues.test.ts +91 -16
  124. package/src/utils/update-elements-with-issues.ts +40 -20
  125. package/src/validate-options.ts +44 -0
  126. package/dist/elements/accented-container.d.ts.map +0 -1
  127. package/dist/elements/accented-container.js +0 -131
  128. package/dist/elements/accented-container.js.map +0 -1
  129. package/src/elements/accented-container.ts +0 -147
@@ -0,0 +1,58 @@
1
+ import isHtmlElement from './is-html-element.js';
2
+ // https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_display/Containing_block#identifying_the_containing_block
3
+ function isContainingBlock(element, win) {
4
+ const style = win.getComputedStyle(element);
5
+ const { transform, perspective } = style;
6
+ // TODO: https://github.com/pomerantsev/accented/issues/119
7
+ // Support other types of containing blocks
8
+ return transform !== 'none'
9
+ || perspective !== 'none';
10
+ }
11
+ function getNonInitialContainingBlock(element, win) {
12
+ let currentElement = element;
13
+ while (currentElement?.parentElement) {
14
+ currentElement = currentElement.parentElement;
15
+ if (isContainingBlock(currentElement, win)) {
16
+ return currentElement;
17
+ }
18
+ }
19
+ return null;
20
+ }
21
+ export default function getElementPosition(element, win) {
22
+ const nonInitialContainingBlock = getNonInitialContainingBlock(element, win);
23
+ // If an element has an ancestor whose transform is not 'none',
24
+ // fixed positioning works differently.
25
+ // https://achrafkassioui.com/blog/position-fixed-and-CSS-transforms/
26
+ if (nonInitialContainingBlock) {
27
+ if (isHtmlElement(element)) {
28
+ const width = element.offsetWidth;
29
+ const height = element.offsetHeight;
30
+ let left = element.offsetLeft;
31
+ let top = element.offsetTop;
32
+ let currentElement = element.offsetParent;
33
+ // Non-initial containing block may not be an offset parent, we have to account for that as well.
34
+ while (currentElement && currentElement !== nonInitialContainingBlock) {
35
+ left += currentElement.offsetLeft;
36
+ top += currentElement.offsetTop;
37
+ currentElement = currentElement.offsetParent;
38
+ }
39
+ return { top, left, width, height };
40
+ }
41
+ else {
42
+ // TODO: https://github.com/pomerantsev/accented/issues/116
43
+ // This is half-baked. It works incorrectly with scaled / rotated elements with issues.
44
+ const elementRect = element.getBoundingClientRect();
45
+ const nonInitialContainingBlockRect = nonInitialContainingBlock.getBoundingClientRect();
46
+ return {
47
+ top: elementRect.top - nonInitialContainingBlockRect.top,
48
+ height: elementRect.height,
49
+ left: elementRect.left - nonInitialContainingBlockRect.left,
50
+ width: elementRect.width
51
+ };
52
+ }
53
+ }
54
+ else {
55
+ return element.getBoundingClientRect();
56
+ }
57
+ }
58
+ //# sourceMappingURL=get-element-position.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-element-position.js","sourceRoot":"","sources":["../../src/utils/get-element-position.ts"],"names":[],"mappings":"AACA,OAAO,aAAa,MAAM,sBAAsB,CAAC;AAEjD,iHAAiH;AACjH,SAAS,iBAAiB,CAAC,OAAgB,EAAE,GAAW;IACtD,MAAM,KAAK,GAAG,GAAG,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAC5C,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,KAAK,CAAC;IACzC,2DAA2D;IAC3D,2CAA2C;IAC3C,OAAO,SAAS,KAAK,MAAM;WACtB,WAAW,KAAK,MAAM,CAAC;AAC9B,CAAC;AAED,SAAS,4BAA4B,CAAC,OAAgB,EAAE,GAAW;IACjE,IAAI,cAAc,GAAmB,OAAO,CAAC;IAC7C,OAAO,cAAc,EAAE,aAAa,EAAE,CAAC;QACrC,cAAc,GAAG,cAAc,CAAC,aAAa,CAAC;QAC9C,IAAI,iBAAiB,CAAC,cAAc,EAAE,GAAG,CAAC,EAAE,CAAC;YAC3C,OAAO,cAAc,CAAC;QACxB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,OAAgB,EAAE,GAAW;IACtE,MAAM,yBAAyB,GAAG,4BAA4B,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAC7E,+DAA+D;IAC/D,uCAAuC;IACvC,qEAAqE;IACrE,IAAI,yBAAyB,EAAE,CAAC;QAC9B,IAAI,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC;YAC3B,MAAM,KAAK,GAAG,OAAO,CAAC,WAAW,CAAC;YAClC,MAAM,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;YACpC,IAAI,IAAI,GAAG,OAAO,CAAC,UAAU,CAAC;YAC9B,IAAI,GAAG,GAAG,OAAO,CAAC,SAAS,CAAC;YAC5B,IAAI,cAAc,GAAG,OAAO,CAAC,YAAkC,CAAC;YAChE,iGAAiG;YACjG,OAAO,cAAc,IAAI,cAAc,KAAK,yBAAyB,EAAE,CAAC;gBACtE,IAAI,IAAI,cAAc,CAAC,UAAU,CAAC;gBAClC,GAAG,IAAI,cAAc,CAAC,SAAS,CAAC;gBAChC,cAAc,GAAG,cAAc,CAAC,YAAkC,CAAC;YACrE,CAAC;YACD,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;QACtC,CAAC;aAAM,CAAC;YACN,2DAA2D;YAC3D,uFAAuF;YACvF,MAAM,WAAW,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC;YACpD,MAAM,6BAA6B,GAAG,yBAAyB,CAAC,qBAAqB,EAAE,CAAC;YACxF,OAAO;gBACL,GAAG,EAAE,WAAW,CAAC,GAAG,GAAG,6BAA6B,CAAC,GAAG;gBACxD,MAAM,EAAE,WAAW,CAAC,MAAM;gBAC1B,IAAI,EAAE,WAAW,CAAC,IAAI,GAAG,6BAA6B,CAAC,IAAI;gBAC3D,KAAK,EAAE,WAAW,CAAC,KAAK;aACzB,CAAC;QACJ,CAAC;IACH,CAAC;SAAM,CAAC;QACN,OAAO,OAAO,CAAC,qBAAqB,EAAE,CAAC;IACzC,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export default function getScrollableAncestors(element: HTMLElement, win: Window): Set<HTMLElement>;
2
+ //# sourceMappingURL=get-scrollable-ancestors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-scrollable-ancestors.d.ts","sourceRoot":"","sources":["../../src/utils/get-scrollable-ancestors.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,OAAO,UAAU,sBAAsB,CAAE,OAAO,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,oBAWhF"}
@@ -0,0 +1,15 @@
1
+ const scrollableOverflowValues = new Set(['auto', 'scroll', 'hidden']);
2
+ export default function getScrollableAncestors(element, win) {
3
+ let currentElement = element;
4
+ let scrollableAncestors = new Set();
5
+ while (currentElement.parentElement) {
6
+ currentElement = currentElement.parentElement;
7
+ const computedStyle = win.getComputedStyle(currentElement);
8
+ if (scrollableOverflowValues.has(computedStyle.overflowX) || scrollableOverflowValues.has(computedStyle.overflowY)) {
9
+ scrollableAncestors.add(currentElement);
10
+ }
11
+ }
12
+ return scrollableAncestors;
13
+ }
14
+ ;
15
+ //# sourceMappingURL=get-scrollable-ancestors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-scrollable-ancestors.js","sourceRoot":"","sources":["../../src/utils/get-scrollable-ancestors.ts"],"names":[],"mappings":"AAAA,MAAM,wBAAwB,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;AAEvE,MAAM,CAAC,OAAO,UAAU,sBAAsB,CAAE,OAAoB,EAAE,GAAW;IAC/E,IAAI,cAAc,GAAG,OAAO,CAAC;IAC7B,IAAI,mBAAmB,GAAG,IAAI,GAAG,EAAe,CAAC;IACjD,OAAO,cAAc,CAAC,aAAa,EAAE,CAAC;QACpC,cAAc,GAAG,cAAc,CAAC,aAAa,CAAC;QAC9C,MAAM,aAAa,GAAG,GAAG,CAAC,gBAAgB,CAAC,cAAc,CAAC,CAAC;QAC3D,IAAI,wBAAwB,CAAC,GAAG,CAAC,aAAa,CAAC,SAAS,CAAC,IAAI,wBAAwB,CAAC,GAAG,CAAC,aAAa,CAAC,SAAS,CAAC,EAAE,CAAC;YACnH,mBAAmB,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC;IACD,OAAO,mBAAmB,CAAC;AAC7B,CAAC;AAAA,CAAC"}
@@ -0,0 +1,2 @@
1
+ export default function isHtmlElement(element: Element): element is HTMLElement;
2
+ //# sourceMappingURL=is-html-element.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is-html-element.d.ts","sourceRoot":"","sources":["../../src/utils/is-html-element.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,IAAI,WAAW,CAK9E"}
@@ -0,0 +1,7 @@
1
+ export default function isHtmlElement(element) {
2
+ // We can't use instanceof because it may not work across contexts
3
+ // (such as when an element is moved from an iframe).
4
+ // This heuristic seems to be the most robust and fastest that I could think of.
5
+ return element.constructor.name.startsWith('HTML');
6
+ }
7
+ //# sourceMappingURL=is-html-element.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is-html-element.js","sourceRoot":"","sources":["../../src/utils/is-html-element.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,OAAgB;IACpD,kEAAkE;IAClE,qDAAqD;IACrD,gFAAgF;IAChF,OAAO,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;AACrD,CAAC"}
@@ -0,0 +1,2 @@
1
+ export default function recalculatePositions(): void;
2
+ //# sourceMappingURL=recalculate-positions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recalculate-positions.d.ts","sourceRoot":"","sources":["../../src/utils/recalculate-positions.ts"],"names":[],"mappings":"AAOA,MAAM,CAAC,OAAO,UAAU,oBAAoB,SAmB3C"}
@@ -0,0 +1,27 @@
1
+ import { batch } from '@preact/signals-core';
2
+ import { extendedElementsWithIssues } from '../state.js';
3
+ import getElementPosition from './get-element-position.js';
4
+ import logAndRethrow from '../log-and-rethrow.js';
5
+ let frameRequested = false;
6
+ export default function recalculatePositions() {
7
+ if (frameRequested) {
8
+ return;
9
+ }
10
+ frameRequested = true;
11
+ window.requestAnimationFrame(() => {
12
+ try {
13
+ frameRequested = false;
14
+ batch(() => {
15
+ extendedElementsWithIssues.value.forEach(({ element, position, visible }) => {
16
+ if (visible.value && element.isConnected) {
17
+ position.value = getElementPosition(element, window);
18
+ }
19
+ });
20
+ });
21
+ }
22
+ catch (error) {
23
+ logAndRethrow(error);
24
+ }
25
+ });
26
+ }
27
+ //# sourceMappingURL=recalculate-positions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recalculate-positions.js","sourceRoot":"","sources":["../../src/utils/recalculate-positions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAC7C,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,kBAAkB,MAAM,2BAA2B,CAAC;AAC3D,OAAO,aAAa,MAAM,uBAAuB,CAAC;AAElD,IAAI,cAAc,GAAG,KAAK,CAAC;AAE3B,MAAM,CAAC,OAAO,UAAU,oBAAoB;IAC1C,IAAI,cAAc,EAAE,CAAC;QACnB,OAAO;IACT,CAAC;IACD,cAAc,GAAG,IAAI,CAAC;IACtB,MAAM,CAAC,qBAAqB,CAAC,GAAG,EAAE;QAChC,IAAI,CAAC;YACH,cAAc,GAAG,KAAK,CAAC;YACvB,KAAK,CAAC,GAAG,EAAE;gBACT,0BAA0B,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE;oBAC1E,IAAI,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;wBACzC,QAAQ,CAAC,KAAK,GAAG,kBAAkB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;oBACvD,CAAC;gBACH,CAAC,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,aAAa,CAAC,KAAK,CAAC,CAAC;QACvB,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,2 @@
1
+ export default function recalculateScrollableAncestors(): void;
2
+ //# sourceMappingURL=recalculate-scrollable-ancestors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recalculate-scrollable-ancestors.d.ts","sourceRoot":"","sources":["../../src/utils/recalculate-scrollable-ancestors.ts"],"names":[],"mappings":"AAIA,MAAM,CAAC,OAAO,UAAU,8BAA8B,SAQrD"}
@@ -0,0 +1,13 @@
1
+ import { batch } from '@preact/signals-core';
2
+ import { extendedElementsWithIssues } from '../state.js';
3
+ import getScrollableAncestors from './get-scrollable-ancestors.js';
4
+ export default function recalculateScrollableAncestors() {
5
+ batch(() => {
6
+ extendedElementsWithIssues.value.forEach(({ element, scrollableAncestors }) => {
7
+ if (element.isConnected) {
8
+ scrollableAncestors.value = getScrollableAncestors(element, window);
9
+ }
10
+ });
11
+ });
12
+ }
13
+ //# sourceMappingURL=recalculate-scrollable-ancestors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recalculate-scrollable-ancestors.js","sourceRoot":"","sources":["../../src/utils/recalculate-scrollable-ancestors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAC7C,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,sBAAsB,MAAM,+BAA+B,CAAC;AAEnE,MAAM,CAAC,OAAO,UAAU,8BAA8B;IACpD,KAAK,CAAC,GAAG,EAAE;QACT,0BAA0B,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,mBAAmB,EAAE,EAAE,EAAE;YAC5E,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;gBACxB,mBAAmB,CAAC,KAAK,GAAG,sBAAsB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YACtE,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,6 @@
1
+ type WindowWithCSS = Window & {
2
+ CSS: typeof CSS;
3
+ };
4
+ export default function supportsAnchorPositioning(win: WindowWithCSS): boolean;
5
+ export {};
6
+ //# sourceMappingURL=supports-anchor-positioning.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supports-anchor-positioning.d.ts","sourceRoot":"","sources":["../../src/utils/supports-anchor-positioning.ts"],"names":[],"mappings":"AAAA,KAAK,aAAa,GAAG,MAAM,GAAG;IAC5B,GAAG,EAAE,OAAO,GAAG,CAAA;CAChB,CAAA;AAED,MAAM,CAAC,OAAO,UAAU,yBAAyB,CAAC,GAAG,EAAE,aAAa,WAEnE"}
@@ -0,0 +1,4 @@
1
+ export default function supportsAnchorPositioning(win) {
2
+ return win.CSS.supports('anchor-name: --foo') && win.CSS.supports('position-anchor: --foo');
3
+ }
4
+ //# sourceMappingURL=supports-anchor-positioning.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supports-anchor-positioning.js","sourceRoot":"","sources":["../../src/utils/supports-anchor-positioning.ts"],"names":[],"mappings":"AAIA,MAAM,CAAC,OAAO,UAAU,yBAAyB,CAAC,GAAkB;IAClE,OAAO,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,oBAAoB,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,wBAAwB,CAAC,CAAC;AAC9F,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"transform-violations.d.ts","sourceRoot":"","sources":["../../src/utils/transform-violations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,KAAK,EAAS,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAEzD,MAAM,CAAC,OAAO,UAAU,mBAAmB,CAAC,UAAU,EAAE,OAAO,UAAU,CAAC,UAAU,uBAyCnF"}
1
+ {"version":3,"file":"transform-violations.d.ts","sourceRoot":"","sources":["../../src/utils/transform-violations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAe,MAAM,UAAU,CAAC;AACxD,OAAO,KAAK,EAAS,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAOzD,MAAM,CAAC,OAAO,UAAU,mBAAmB,CAAC,UAAU,EAAE,OAAO,UAAU,CAAC,UAAU,uBA+CnF"}
@@ -1,3 +1,7 @@
1
+ function impactCompare(a, b) {
2
+ const impactOrder = [null, 'minor', 'moderate', 'serious', 'critical'];
3
+ return impactOrder.indexOf(a) - impactOrder.indexOf(b);
4
+ }
1
5
  export default function transformViolations(violations) {
2
6
  const elementsWithIssues = [];
3
7
  for (const violation of violations) {
@@ -34,6 +38,11 @@ export default function transformViolations(violations) {
34
38
  }
35
39
  }
36
40
  }
41
+ for (const elementWithIssues of elementsWithIssues) {
42
+ elementWithIssues.issues.sort((a, b) => {
43
+ return -impactCompare(a.impact, b.impact) || a.id.localeCompare(b.id);
44
+ });
45
+ }
37
46
  return elementsWithIssues;
38
47
  }
39
48
  //# sourceMappingURL=transform-violations.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"transform-violations.js","sourceRoot":"","sources":["../../src/utils/transform-violations.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,OAAO,UAAU,mBAAmB,CAAC,UAAwC;IAClF,MAAM,kBAAkB,GAA6B,EAAE,CAAC;IAExD,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,KAAK,EAAE,CAAC;YACnC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;YAEjC,4EAA4E;YAC5E,8EAA8E;YAC9E,2CAA2C;YAC3C,mGAAmG;YACnG,yEAAyE;YACzE,sHAAsH;YACtH,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;YAErC,kHAAkH;YAClH,kEAAkE;YAClE,MAAM,aAAa,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;YAE/C,IAAI,OAAO,IAAI,CAAC,UAAU,IAAI,CAAC,aAAa,EAAE,CAAC;gBAC7C,MAAM,KAAK,GAAU;oBACnB,EAAE,EAAE,SAAS,CAAC,EAAE;oBAChB,KAAK,EAAE,SAAS,CAAC,IAAI;oBACrB,WAAW,EAAE,IAAI,CAAC,cAAc,IAAI,SAAS,CAAC,WAAW;oBACzD,GAAG,EAAE,SAAS,CAAC,OAAO;oBACtB,MAAM,EAAE,SAAS,CAAC,MAAM,IAAI,IAAI;iBACjC,CAAC;gBACF,MAAM,oBAAoB,GAAG,kBAAkB,CAAC,SAAS,CAAC,iBAAiB,CAAC,EAAE,CAAC,iBAAiB,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC;gBACtH,IAAI,oBAAoB,KAAK,CAAC,CAAC,EAAE,CAAC;oBAChC,kBAAkB,CAAC,IAAI,CAAC;wBACtB,OAAO;wBACP,MAAM,EAAE,CAAC,KAAK,CAAC;qBAChB,CAAC,CAAC;gBACL,CAAC;qBAAM,CAAC;oBACN,kBAAkB,CAAC,oBAAoB,CAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAC/D,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,kBAAkB,CAAC;AAC5B,CAAC"}
1
+ {"version":3,"file":"transform-violations.js","sourceRoot":"","sources":["../../src/utils/transform-violations.ts"],"names":[],"mappings":"AAGA,SAAS,aAAa,CAAC,CAAc,EAAE,CAAc;IACnD,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IACvE,OAAO,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,CAAC,OAAO,UAAU,mBAAmB,CAAC,UAAwC;IAClF,MAAM,kBAAkB,GAA6B,EAAE,CAAC;IAExD,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,KAAK,EAAE,CAAC;YACnC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;YAEjC,4EAA4E;YAC5E,8EAA8E;YAC9E,2CAA2C;YAC3C,mGAAmG;YACnG,yEAAyE;YACzE,sHAAsH;YACtH,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;YAErC,kHAAkH;YAClH,kEAAkE;YAClE,MAAM,aAAa,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;YAE/C,IAAI,OAAO,IAAI,CAAC,UAAU,IAAI,CAAC,aAAa,EAAE,CAAC;gBAC7C,MAAM,KAAK,GAAU;oBACnB,EAAE,EAAE,SAAS,CAAC,EAAE;oBAChB,KAAK,EAAE,SAAS,CAAC,IAAI;oBACrB,WAAW,EAAE,IAAI,CAAC,cAAc,IAAI,SAAS,CAAC,WAAW;oBACzD,GAAG,EAAE,SAAS,CAAC,OAAO;oBACtB,MAAM,EAAE,SAAS,CAAC,MAAM,IAAI,IAAI;iBACjC,CAAC;gBACF,MAAM,oBAAoB,GAAG,kBAAkB,CAAC,SAAS,CAAC,iBAAiB,CAAC,EAAE,CAAC,iBAAiB,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC;gBACtH,IAAI,oBAAoB,KAAK,CAAC,CAAC,EAAE,CAAC;oBAChC,kBAAkB,CAAC,IAAI,CAAC;wBACtB,OAAO;wBACP,MAAM,EAAE,CAAC,KAAK,CAAC;qBAChB,CAAC,CAAC;gBACL,CAAC;qBAAM,CAAC;oBACN,kBAAkB,CAAC,oBAAoB,CAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAC/D,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAK,MAAM,iBAAiB,IAAI,kBAAkB,EAAE,CAAC;QACnD,iBAAiB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACrC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACxE,CAAC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,kBAAkB,CAAC;AAC5B,CAAC"}
@@ -1,5 +1,7 @@
1
1
  import type { AxeResults } from 'axe-core';
2
2
  import type { Signal } from '@preact/signals-core';
3
3
  import type { ExtendedElementWithIssues } from '../types';
4
- export default function updateElementsWithIssues(extendedElementsWithIssues: Signal<Array<ExtendedElementWithIssues>>, violations: typeof AxeResults.violations, win: Window, name: string): void;
4
+ export default function updateElementsWithIssues(extendedElementsWithIssues: Signal<Array<ExtendedElementWithIssues>>, violations: typeof AxeResults.violations, win: Window & {
5
+ CSS: typeof CSS;
6
+ }, name: string): void;
5
7
  //# sourceMappingURL=update-elements-with-issues.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"update-elements-with-issues.d.ts","sourceRoot":"","sources":["../../src/utils/update-elements-with-issues.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAC;AAO1D,MAAM,CAAC,OAAO,UAAU,wBAAwB,CAAC,0BAA0B,EAAE,MAAM,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC,EAAE,UAAU,EAAE,OAAO,UAAU,CAAC,UAAU,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,QA4CzL"}
1
+ {"version":3,"file":"update-elements-with-issues.d.ts","sourceRoot":"","sources":["../../src/utils/update-elements-with-issues.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAC;AAW1D,MAAM,CAAC,OAAO,UAAU,wBAAwB,CAAC,0BAA0B,EAAE,MAAM,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC,EAAE,UAAU,EAAE,OAAO,UAAU,CAAC,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG;IAAE,GAAG,EAAE,OAAO,GAAG,CAAA;CAAE,EAAE,IAAI,EAAE,MAAM,QA4D/M"}
@@ -1,6 +1,9 @@
1
1
  import { batch, signal } from '@preact/signals-core';
2
2
  import transformViolations from './transform-violations.js';
3
3
  import areIssueSetsEqual from './are-issue-sets-equal.js';
4
+ import getElementPosition from './get-element-position.js';
5
+ import getScrollableAncestors from './get-scrollable-ancestors.js';
6
+ import supportsAnchorPositioning from './supports-anchor-positioning.js';
4
7
  let count = 0;
5
8
  export default function updateElementsWithIssues(extendedElementsWithIssues, violations, win, name) {
6
9
  const updatedElementsWithIssues = transformViolations(violations);
@@ -22,21 +25,36 @@ export default function updateElementsWithIssues(extendedElementsWithIssues, vio
22
25
  .filter(extendedElementWithIssues => {
23
26
  return !removedElementsWithIssues.some(removedElementWithIssues => removedElementWithIssues.element === extendedElementWithIssues.element);
24
27
  })
25
- .concat(addedElementsWithIssues.map(addedElementWithIssues => {
28
+ .concat(addedElementsWithIssues
29
+ .filter(addedElementWithIssues => addedElementWithIssues.element.isConnected)
30
+ .map(addedElementWithIssues => {
26
31
  const id = count++;
27
- const accentedContainer = win.document.createElement(`${name}-container`);
32
+ const trigger = win.document.createElement(`${name}-trigger`);
28
33
  const elementZIndex = parseInt(win.getComputedStyle(addedElementWithIssues.element).zIndex, 10);
29
34
  if (!isNaN(elementZIndex)) {
30
- accentedContainer.style.setProperty('z-index', (elementZIndex + 1).toString());
35
+ trigger.style.setProperty('z-index', (elementZIndex + 1).toString(), 'important');
31
36
  }
32
- accentedContainer.style.setProperty('position-anchor', `--${name}-anchor-${id}`);
33
- accentedContainer.dataset.id = id.toString();
37
+ trigger.style.setProperty('position-anchor', `--${name}-anchor-${id}`, 'important');
38
+ trigger.dataset.id = id.toString();
39
+ const accentedDialog = win.document.createElement(`${name}-dialog`);
40
+ trigger.dialog = accentedDialog;
41
+ const position = getElementPosition(addedElementWithIssues.element, win);
42
+ trigger.position = signal(position);
43
+ trigger.visible = signal(true);
44
+ trigger.element = addedElementWithIssues.element;
45
+ const scrollableAncestors = supportsAnchorPositioning(win) ?
46
+ new Set() :
47
+ getScrollableAncestors(addedElementWithIssues.element, win);
34
48
  const issues = signal(addedElementWithIssues.issues);
35
- accentedContainer.issues = issues;
49
+ accentedDialog.issues = issues;
50
+ accentedDialog.element = addedElementWithIssues.element;
36
51
  return {
37
52
  id,
38
53
  element: addedElementWithIssues.element,
39
- accentedContainer,
54
+ visible: trigger.visible,
55
+ position: trigger.position,
56
+ scrollableAncestors: signal(scrollableAncestors),
57
+ trigger,
40
58
  issues
41
59
  };
42
60
  }));
@@ -1 +1 @@
1
- {"version":3,"file":"update-elements-with-issues.js","sourceRoot":"","sources":["../../src/utils/update-elements-with-issues.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"update-elements-with-issues.js","sourceRoot":"","sources":["../../src/utils/update-elements-with-issues.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { AccentedOptions } from './types';
2
+ export default function validateOptions(options: AccentedOptions): void;
3
+ //# sourceMappingURL=validate-options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-options.d.ts","sourceRoot":"","sources":["../src/validate-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAQ/C,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,OAAO,EAAE,eAAe,QAmC/D"}
@@ -0,0 +1,42 @@
1
+ import { allowedAxeOptions } from './types.js';
2
+ // The space of valid CSS and HTML names is wider than this,
3
+ // but with Unicode it gets complicated quickly, so I'm sticking to only allowing
4
+ // lowercase alphanumeric names that possibly contain dashes that start with a letter.
5
+ const nameRegex = /^[a-z]([a-z0-9]|-)+$/;
6
+ export default function validateOptions(options) {
7
+ if (typeof options !== 'object' || options === null) {
8
+ throw new TypeError(`Accented: invalid argument. The options parameter must be an object if provided. It’s currently set to ${options}.`);
9
+ }
10
+ if (options.throttle !== undefined) {
11
+ if (typeof options.throttle !== 'object' || options.throttle === null) {
12
+ throw new TypeError(`Accented: invalid argument. \`throttle\` option must be an object if provided. It’s currently set to ${options.throttle}.`);
13
+ }
14
+ if (options.throttle.wait !== undefined && (typeof options.throttle.wait !== 'number' || options.throttle.wait < 0)) {
15
+ throw new TypeError(`Accented: invalid argument. \`throttle.wait\` option must be a non-negative number if provided. It’s currently set to ${options.throttle.wait}.`);
16
+ }
17
+ }
18
+ if (options.output !== undefined) {
19
+ if (typeof options.output !== 'object' || options.output === null) {
20
+ throw new TypeError(`Accented: invalid argument. \`output\` option must be an object if provided. It’s currently set to ${options.output}.`);
21
+ }
22
+ if (options.output.console !== undefined && typeof options.output.console !== 'boolean') {
23
+ console.warn(`Accented: invalid argument. \`output.console\` option is expected to be a boolean. It’s currently set to ${options.output.console}.`);
24
+ }
25
+ }
26
+ if (options.callback !== undefined && typeof options.callback !== 'function') {
27
+ throw new TypeError(`Accented: invalid argument. \`callback\` option must be a function if provided. It’s currently set to ${options.callback}.`);
28
+ }
29
+ if (options.name !== undefined && (typeof options.name !== 'string' || !options.name.match(nameRegex))) {
30
+ throw new TypeError(`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}.`);
31
+ }
32
+ if (options.axeOptions !== undefined) {
33
+ if (typeof options.axeOptions !== 'object' || options.axeOptions === null) {
34
+ throw new TypeError(`Accented: invalid argument. \`axeOptions\` option must be an object if provided. It’s currently set to ${options.axeOptions}.`);
35
+ }
36
+ const unsupportedKeys = Object.keys(options.axeOptions).filter(key => !allowedAxeOptions.includes(key));
37
+ if (unsupportedKeys.length > 0) {
38
+ throw new TypeError(`Accented: invalid argument. \`axeOptions\` contains the following unsupported keys: ${unsupportedKeys.join(', ')}. Valid options are: ${allowedAxeOptions.join(', ')}.`);
39
+ }
40
+ }
41
+ }
42
+ //# sourceMappingURL=validate-options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-options.js","sourceRoot":"","sources":["../src/validate-options.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "accented",
3
- "version": "0.0.0-20250124142030",
3
+ "version": "0.0.0-20250303013509",
4
4
  "description": "Continuous accessibility testing and issue highlighting for web development",
5
5
  "type": "module",
6
6
  "main": "dist/accented.js",
@@ -32,6 +32,7 @@
32
32
  "build": "tsc",
33
33
  "checkBuiltFiles": "node --import tsx ./scripts/check-built-files.ts",
34
34
  "checkImportsInBuiltFiles": "node ./dist/accented.js",
35
+ "typecheckTests": "tsc -p ./tsconfig.test.json",
35
36
  "watch": "tsc --watch",
36
37
  "test": "node --test --import tsx \"./**/*.test.ts\""
37
38
  }
package/src/accented.ts CHANGED
@@ -1,29 +1,20 @@
1
1
 
2
+ import registerElements from './register-elements.js';
2
3
  import createDomUpdater from './dom-updater.js';
3
4
  import createLogger from './logger.js';
4
5
  import createScanner from './scanner.js';
6
+ import setupScrollListeners from './scroll-listeners.js';
7
+ import setupResizeListener from './resize-listener.js';
8
+ import setupIntersectionObserver from './intersection-observer.js';
5
9
  import { enabled, extendedElementsWithIssues } from './state.js';
6
10
  import deepMerge from './utils/deep-merge.js';
7
- import getAccentedContainer from './elements/accented-container.js'
8
- import type { DeepRequired, AccentedOptions, DisableAccented } from './types';
11
+ import type { AccentedOptions, DisableAccented } from './types';
12
+ import validateOptions from './validate-options.js';
13
+ import supportsAnchorPositioning from './utils/supports-anchor-positioning.js';
14
+ import logAndRethrow from './log-and-rethrow.js';
9
15
 
10
16
  export type { AccentedOptions, DisableAccented };
11
17
 
12
- // IMPORTANT: when changing any of the properties or values, also do the following:
13
- // * update the default value in the type documentation accordingly;
14
- // * update validations and validation tests if necessary;
15
- // * update examples in the accented() function JSDoc;
16
- // * update examples in the Readme.
17
- const defaultOptions: DeepRequired<AccentedOptions> = {
18
- name: 'accented',
19
- outputToConsole: true,
20
- throttle: {
21
- wait: 1000,
22
- leading: true
23
- },
24
- callback: () => {}
25
- };
26
-
27
18
  /**
28
19
  * Enables highlighting of elements with accessibility issues.
29
20
  *
@@ -36,7 +27,9 @@ const defaultOptions: DeepRequired<AccentedOptions> = {
36
27
  *
37
28
  * @example
38
29
  * const disableAccented = accented({
39
- * outputToConsole: false,
30
+ * output: {
31
+ * console: false
32
+ * },
40
33
  * throttle: {
41
34
  * wait: 500,
42
35
  * leading: false
@@ -49,51 +42,78 @@ const defaultOptions: DeepRequired<AccentedOptions> = {
49
42
  */
50
43
  export default function accented(options: AccentedOptions = {}): DisableAccented {
51
44
 
52
- // Argument validation
53
- if (options.throttle !== undefined) {
54
- if (typeof options.throttle !== 'object' || options.throttle === null) {
55
- throw new TypeError(`Invalid argument: \`throttle\` option must be an object if provided. It’s currently set to ${options.throttle}.`);
56
- }
57
- if (options.throttle.wait !== undefined && (typeof options.throttle.wait !== 'number' || options.throttle.wait < 0)) {
58
- throw new TypeError(`Invalid argument: \`throttle.wait\` option must be a non-negative number if provided. It’s currently set to ${options.throttle.wait}.`);
59
- }
60
- if (options.callback !== undefined && typeof options.callback !== 'function') {
61
- throw new TypeError(`Invalid argument: \`callback\` option must be a function if provided. It’s currently set to ${options.callback}.`);
45
+ validateOptions(options);
46
+
47
+ try {
48
+ if (typeof window === 'undefined' || typeof document === 'undefined') {
49
+ console.warn('Accented: this script can only run in the browser, and it’s likely running on the server now. Exiting.');
50
+ console.trace();
51
+ return () => {};
62
52
  }
63
- }
64
53
 
65
- if (typeof window === 'undefined' || typeof document === 'undefined') {
66
- console.warn('Accented: this script can only run in the browser, and it’s likely running on the server now. Exiting.');
67
- console.trace();
68
- return () => {};
69
- }
54
+ const defaultOutput: Required<AccentedOptions['output']> = {
55
+ console: true
56
+ };
70
57
 
71
- const {name, outputToConsole, throttle, callback} = deepMerge(defaultOptions, options);
58
+ const defaultThrottle: Required<AccentedOptions['throttle']> = {
59
+ wait: 1000,
60
+ leading: true
61
+ };
72
62
 
73
- const AccentedContainer = getAccentedContainer(name);
74
- if (!customElements.get(`${name}-container`)) {
75
- customElements.define(`${name}-container`, AccentedContainer);
76
- }
63
+ // IMPORTANT: when changing any of the properties or values, also do the following:
64
+ // * update the default value in the type documentation accordingly;
65
+ // * update validations and validation tests if necessary;
66
+ // * update examples in the accented() function JSDoc;
67
+ // * update examples in the Readme.
68
+ const defaultOptions: Required<AccentedOptions> = {
69
+ axeContext: document,
70
+ axeOptions: {},
71
+ name: 'accented',
72
+ output: defaultOutput,
73
+ throttle: defaultThrottle,
74
+ callback: () => {}
75
+ };
77
76
 
78
- if (enabled.value) {
79
- // TODO: add link to relevant docs
80
- console.warn(
81
- 'You are trying to run the Accented library more than once. ' +
82
- 'This will likely lead to errors.'
83
- );
84
- console.trace();
85
- }
77
+ const {axeContext, axeOptions, name, output, throttle, callback} = deepMerge(defaultOptions, options);
78
+
79
+ if (enabled.value) {
80
+ // Add link to the recipes section of the docs (#56).
81
+ console.warn(
82
+ 'You are trying to run the Accented library more than once. ' +
83
+ 'This will likely lead to errors.'
84
+ );
85
+ console.trace();
86
+ }
86
87
 
87
- enabled.value = true;
88
- const cleanupScanner = createScanner(name, throttle, callback);
89
- const cleanupDomUpdater = createDomUpdater(name);
90
- const cleanupLogger = outputToConsole ? createLogger() : () => {};
88
+ enabled.value = true;
91
89
 
92
- return () => {
93
- enabled.value = false;
94
- extendedElementsWithIssues.value = [];
95
- cleanupScanner();
96
- cleanupDomUpdater();
97
- cleanupLogger();
98
- };
90
+ registerElements(name);
91
+
92
+ const {disconnect: cleanupIntersectionObserver, intersectionObserver } = supportsAnchorPositioning(window) ? {} : setupIntersectionObserver();
93
+ const cleanupScanner = createScanner(name, axeContext, axeOptions, throttle, callback);
94
+ const cleanupDomUpdater = createDomUpdater(name, intersectionObserver);
95
+ const cleanupLogger = output.console ? createLogger() : () => {};
96
+ const cleanupScrollListeners = supportsAnchorPositioning(window) ? () => {} : setupScrollListeners();
97
+ const cleanupResizeListener = supportsAnchorPositioning(window) ? () => {} : setupResizeListener();
98
+
99
+ return () => {
100
+ try {
101
+ enabled.value = false;
102
+ extendedElementsWithIssues.value = [];
103
+ cleanupScanner();
104
+ cleanupDomUpdater();
105
+ cleanupLogger();
106
+ cleanupScrollListeners();
107
+ cleanupResizeListener();
108
+ if (cleanupIntersectionObserver) {
109
+ cleanupIntersectionObserver();
110
+ }
111
+ } catch (error) {
112
+ logAndRethrow(error);
113
+ }
114
+ };
115
+ } catch (error) {
116
+ logAndRethrow(error);
117
+ return () => {};
118
+ }
99
119
  }
@@ -0,0 +1,2 @@
1
+ export const accentedUrl = 'https://www.npmjs.com/package/accented';
2
+ export const issuesUrl = 'https://github.com/pomerantsev/accented/issues';