abledom 0.5.0 → 0.6.1

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/dist/esm/index.js CHANGED
@@ -58,7 +58,10 @@ var ValidationRule = class {
58
58
  };
59
59
 
60
60
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/ui.css
61
- var ui_default = "#abledom-report {\n bottom: 20px;\n display: flex;\n flex-direction: column;\n left: 10px;\n max-height: 80%;\n max-width: 60%;\n padding: 4px 8px;\n position: fixed;\n z-index: 100500;\n}\n\n#abledom-report :focus-visible {\n outline: 3px solid red;\n mix-blend-mode: difference;\n}\n\n#abledom-report.abledom-align-left {\n left: 10px;\n right: auto;\n}\n\n#abledom-report.abledom-align-right {\n left: auto;\n right: 10px;\n}\n\n#abledom-report.abledom-align-bottom {\n bottom: 20px;\n top: auto;\n}\n\n#abledom-report.abledom-align-top {\n /* flex-direction: column-reverse; */\n bottom: auto;\n top: 10px;\n}\n\n.abledom-menu-container {\n backdrop-filter: blur(3px);\n border-radius: 8px;\n box-shadow: 0px 0px 4px rgba(127, 127, 127, 0.5);\n display: inline-block;\n margin: 2px auto 2px 0;\n}\n\n#abledom-report.abledom-align-right .abledom-menu-container {\n margin: 2px 0 2px auto;\n}\n\n.abledom-menu {\n background-color: rgba(140, 10, 121, 0.7);\n border-radius: 8px;\n color: white;\n display: inline flex;\n font-family: Arial, Helvetica, sans-serif;\n font-size: 16px;\n line-height: 26px;\n padding: 4px;\n}\n\n.abledom-menu .issues-count {\n margin: 0 8px;\n display: inline-block;\n}\n\n.abledom-menu .button {\n all: unset;\n color: #000;\n cursor: pointer;\n background: linear-gradient(\n 180deg,\n rgba(255, 255, 255, 1) 0%,\n rgba(200, 200, 200, 1) 100%\n );\n border-radius: 6px;\n border: 1px solid rgba(255, 255, 255, 0.4);\n box-sizing: border-box;\n line-height: 0px;\n margin-right: 4px;\n max-height: 26px;\n padding: 2px;\n text-decoration: none;\n}\n\n.abledom-menu .align-button {\n border-right-color: rgba(0, 0, 0, 0.4);\n border-radius: 0;\n margin: 0;\n}\n\n.abledom-menu .align-button:active,\n#abledom-report .pressed {\n background: linear-gradient(\n 180deg,\n rgba(130, 130, 130, 1) 0%,\n rgba(180, 180, 180, 1) 100%\n );\n}\n\n.abledom-menu .align-button-first {\n border-top-left-radius: 6px;\n border-bottom-left-radius: 6px;\n margin-left: 8px;\n}\n.abledom-menu .align-button-last {\n border-top-right-radius: 6px;\n border-bottom-right-radius: 6px;\n border-right-color: rgba(255, 255, 255, 0.4);\n}\n\n.abledom-issues-container {\n overflow: auto;\n max-height: calc(100vh - 100px);\n}\n\n#abledom-report.abledom-align-right .abledom-issues-container {\n text-align: right;\n}\n\n.abledom-issue-container {\n backdrop-filter: blur(3px);\n border-radius: 8px;\n box-shadow: 0px 0px 4px rgba(127, 127, 127, 0.5);\n display: inline-flex;\n margin: 2px 0;\n}\n\n.abledom-issue {\n background-color: rgba(164, 2, 2, 0.7);\n border-radius: 8px;\n color: white;\n display: inline flex;\n font-family: Arial, Helvetica, sans-serif;\n font-size: 16px;\n line-height: 26px;\n padding: 4px;\n}\n.abledom-issue_warning {\n background-color: rgba(163, 82, 1, 0.7);\n}\n.abledom-issue_info {\n background-color: rgba(0, 0, 255, 0.7);\n}\n\n.abledom-issue .button {\n all: unset;\n color: #000;\n cursor: pointer;\n background: linear-gradient(\n 180deg,\n rgba(255, 255, 255, 1) 0%,\n rgba(200, 200, 200, 1) 100%\n );\n border-radius: 6px;\n border: 1px solid rgba(255, 255, 255, 0.4);\n box-sizing: border-box;\n line-height: 0px;\n margin-right: 4px;\n max-height: 26px;\n padding: 2px;\n text-decoration: none;\n}\n\n.abledom-issue .button:hover {\n opacity: 0.7;\n}\n\n.abledom-issue .button.close {\n background: none;\n border-color: transparent;\n color: #fff;\n margin: 0;\n}\n\n.abledom-highlight {\n background-color: yellow;\n box-sizing: border-box;\n display: none;\n opacity: 0.6;\n position: fixed;\n z-index: 100499;\n}\n\n.abledom-highlight-border1 {\n border-top: 2px solid red;\n border-bottom: 2px solid red;\n box-sizing: border-box;\n position: absolute;\n top: -2px;\n width: calc(100% + 20px);\n height: calc(100% + 4px);\n margin: 0 -10px;\n}\n\n.abledom-highlight-border2 {\n border-left: 2px solid red;\n border-right: 2px solid red;\n box-sizing: border-box;\n position: absolute;\n width: calc(100% + 4px);\n left: -2px;\n height: calc(100% + 20px);\n margin: -10px 0;\n}\n";
61
+ var ui_default = "#abledom-report {\n bottom: 20px;\n display: flex;\n flex-direction: column;\n left: 10px;\n max-height: 80%;\n max-width: 60%;\n padding: 4px 8px;\n position: fixed;\n z-index: 100500;\n}\n\n#abledom-report :focus-visible {\n outline: 3px solid red;\n mix-blend-mode: difference;\n}\n\n#abledom-report.abledom-align-left {\n left: 10px;\n right: auto;\n}\n\n#abledom-report.abledom-align-right {\n left: auto;\n right: 10px;\n}\n\n#abledom-report.abledom-align-bottom {\n bottom: 20px;\n top: auto;\n}\n\n#abledom-report.abledom-align-top {\n /* flex-direction: column-reverse; */\n bottom: auto;\n top: 10px;\n}\n\n.abledom-menu-container {\n backdrop-filter: blur(3px);\n border-radius: 8px;\n box-shadow: 0px 0px 4px rgba(127, 127, 127, 0.5);\n display: inline-block;\n margin: 2px auto 2px 0;\n}\n\n#abledom-report.abledom-align-right .abledom-menu-container {\n margin: 2px 0 2px auto;\n}\n\n.abledom-menu {\n background-color: rgba(140, 10, 121, 0.7);\n border-radius: 8px;\n color: white;\n display: inline flex;\n font-family: Arial, Helvetica, sans-serif;\n font-size: 16px;\n line-height: 26px;\n padding: 4px;\n}\n\n.abledom-menu .issues-count {\n margin: 0 8px;\n display: inline-block;\n}\n\n.abledom-menu .button {\n all: unset;\n color: #000;\n cursor: pointer;\n background: linear-gradient(\n 180deg,\n rgba(255, 255, 255, 1) 0%,\n rgba(200, 200, 200, 1) 100%\n );\n border-radius: 6px;\n border: 1px solid rgba(255, 255, 255, 0.4);\n box-sizing: border-box;\n line-height: 0px;\n margin-right: 4px;\n max-height: 26px;\n padding: 2px;\n text-decoration: none;\n}\n\n.abledom-menu .align-button {\n border-right-color: rgba(0, 0, 0, 0.4);\n border-radius: 0;\n margin: 0;\n}\n\n.abledom-menu .align-button:active,\n#abledom-report .pressed {\n background: linear-gradient(\n 180deg,\n rgba(130, 130, 130, 1) 0%,\n rgba(180, 180, 180, 1) 100%\n );\n}\n\n.abledom-menu .align-button-first {\n border-top-left-radius: 6px;\n border-bottom-left-radius: 6px;\n margin-left: 8px;\n}\n.abledom-menu .align-button-last {\n border-top-right-radius: 6px;\n border-bottom-right-radius: 6px;\n border-right-color: rgba(255, 255, 255, 0.4);\n}\n\n.abledom-issues-container {\n overflow: auto;\n max-height: calc(100vh - 100px);\n}\n\n#abledom-report.abledom-align-right .abledom-issues-container {\n text-align: right;\n}\n\n.abledom-issue-container {\n backdrop-filter: blur(3px);\n border-radius: 8px;\n box-shadow: 0px 0px 4px rgba(127, 127, 127, 0.5);\n display: inline-flex;\n margin: 2px 0;\n}\n\n.abledom-issue {\n background-color: rgba(164, 2, 2, 0.7);\n border-radius: 8px;\n color: white;\n display: inline flex;\n font-family: Arial, Helvetica, sans-serif;\n font-size: 16px;\n line-height: 26px;\n padding: 4px;\n}\n.abledom-issue_warning {\n background-color: rgba(163, 82, 1, 0.7);\n}\n.abledom-issue_info {\n background-color: rgba(0, 0, 255, 0.7);\n}\n\n.abledom-issue .button {\n all: unset;\n color: #000;\n cursor: pointer;\n background: linear-gradient(\n 180deg,\n rgba(255, 255, 255, 1) 0%,\n rgba(200, 200, 200, 1) 100%\n );\n border-radius: 6px;\n border: 1px solid rgba(255, 255, 255, 0.4);\n box-sizing: border-box;\n line-height: 0px;\n margin-right: 4px;\n max-height: 26px;\n padding: 2px;\n text-decoration: none;\n}\n\n.abledom-issue .button:hover {\n opacity: 0.7;\n}\n\n.abledom-issue .button.close {\n background: none;\n border-color: transparent;\n color: #fff;\n margin: 0;\n}\n";
62
+
63
+ // inline-file:/Users/marata/Documents/Work/abledom/src/ui/highlighter.css
64
+ var highlighter_default = ".abledom-highlight {\n background-color: yellow;\n box-sizing: border-box;\n display: none;\n opacity: 0.6;\n position: fixed;\n z-index: 100499;\n}\n\n.abledom-highlight-border1 {\n border-top: 2px solid red;\n border-bottom: 2px solid red;\n box-sizing: border-box;\n position: absolute;\n top: -2px;\n width: calc(100% + 20px);\n height: calc(100% + 4px);\n margin: 0 -10px;\n}\n\n.abledom-highlight-border2 {\n border-left: 2px solid red;\n border-right: 2px solid red;\n box-sizing: border-box;\n position: absolute;\n width: calc(100% + 4px);\n left: -2px;\n height: calc(100% + 20px);\n margin: -10px 0;\n}\n";
62
65
 
63
66
  // src/ui/domBuilder.ts
64
67
  var DOMBuilder = class {
@@ -364,8 +367,7 @@ var IssueUI = class {
364
367
  if (element2) {
365
368
  revealButton.onclick = () => {
366
369
  var _a;
367
- element2.scrollIntoView({ block: "center" });
368
- (_a = this._issuesUI) == null ? void 0 : _a.highlight(element2);
370
+ (_a = this._issuesUI) == null ? void 0 : _a.highlight(element2, true);
369
371
  };
370
372
  } else {
371
373
  revealButton.style.display = "none";
@@ -442,7 +444,8 @@ var IssueUI = class {
442
444
  }
443
445
  };
444
446
  var IssuesUI = class {
445
- constructor(win, props) {
447
+ constructor(win, getHighlighter, props) {
448
+ __publicField(this, "_win");
446
449
  __publicField(this, "_container");
447
450
  __publicField(this, "_issuesContainer");
448
451
  __publicField(this, "_menuElement");
@@ -455,9 +458,11 @@ var IssuesUI = class {
455
458
  __publicField(this, "_alignBottomRightButton");
456
459
  __publicField(this, "_isMuted", false);
457
460
  __publicField(this, "_issues", /* @__PURE__ */ new Set());
458
- __publicField(this, "_highlighter");
461
+ __publicField(this, "_getHighlighter");
459
462
  __publicField(this, "bugReport");
460
463
  __publicField(this, "headless");
464
+ this._win = win;
465
+ this._getHighlighter = getHighlighter;
461
466
  this.bugReport = props.bugReport;
462
467
  this.headless = !!props.headless;
463
468
  if (this.headless) {
@@ -578,7 +583,6 @@ var IssuesUI = class {
578
583
  }
579
584
  ).element(alignbottomright_default).closeTag().closeTag();
580
585
  doc.body.appendChild(container);
581
- this._highlighter = new ElementHighlighter(win);
582
586
  }
583
587
  setUIAlignment(alignment) {
584
588
  var _a, _b, _c, _d, _e, _f, _g, _h;
@@ -700,15 +704,15 @@ var IssuesUI = class {
700
704
  });
701
705
  this._setShowHideButtonsVisibility();
702
706
  }
703
- highlight(element) {
704
- var _a;
705
- (_a = this._highlighter) == null ? void 0 : _a.highlight(element);
707
+ highlight(element, scrollIntoView, autoHideTime) {
708
+ var _a, _b;
709
+ (_b = (_a = this._getHighlighter) == null ? void 0 : _a.call(this)) == null ? void 0 : _b.highlight(element, scrollIntoView, autoHideTime);
706
710
  }
707
711
  dispose() {
708
- var _a, _b;
709
- (_a = this._highlighter) == null ? void 0 : _a.dispose();
710
- (_b = this._container) == null ? void 0 : _b.remove();
711
- delete this._highlighter;
712
+ var _a;
713
+ (_a = this._container) == null ? void 0 : _a.remove();
714
+ delete this._win;
715
+ delete this._getHighlighter;
712
716
  delete this._container;
713
717
  delete this._issuesContainer;
714
718
  delete this._menuElement;
@@ -728,6 +732,7 @@ var ElementHighlighter = class {
728
732
  __publicField(this, "_element");
729
733
  __publicField(this, "_cancelScrollTimer");
730
734
  __publicField(this, "_intersectionObserver");
735
+ __publicField(this, "_cancelAutoHideTimer");
731
736
  __publicField(this, "_onScroll", () => {
732
737
  var _a;
733
738
  (_a = this._cancelScrollTimer) == null ? void 0 : _a.call(this);
@@ -748,10 +753,19 @@ var ElementHighlighter = class {
748
753
  const container = this._container = win.document.createElement("div");
749
754
  container.__abledomui = true;
750
755
  container.className = "abledom-highlight";
756
+ const doc = win.document;
757
+ const style = doc.createElement("style");
758
+ style.type = "text/css";
759
+ style.appendChild(doc.createTextNode(highlighter_default));
760
+ container.appendChild(style);
751
761
  new DOMBuilder(container).openTag("div", { class: "abledom-highlight-border1" }).closeTag().openTag("div", { class: "abledom-highlight-border2" }).closeTag();
752
762
  win.addEventListener("scroll", this._onScroll, true);
753
763
  }
754
- highlight(element) {
764
+ highlight(element, scrollIntoView, autoHideTime) {
765
+ var _a;
766
+ if (this._cancelAutoHideTimer && element !== this._element) {
767
+ this._cancelAutoHideTimer();
768
+ }
755
769
  if (!element) {
756
770
  delete this._element;
757
771
  this._unobserve();
@@ -764,6 +778,22 @@ var ElementHighlighter = class {
764
778
  return;
765
779
  }
766
780
  this._element = element;
781
+ if (scrollIntoView) {
782
+ element.scrollIntoView({ block: "center" });
783
+ }
784
+ if (autoHideTime) {
785
+ (_a = this._cancelAutoHideTimer) == null ? void 0 : _a.call(this);
786
+ const autoHideTimeout = win.setTimeout(() => {
787
+ if (this._cancelAutoHideTimer) {
788
+ this.highlight(null);
789
+ delete this._cancelAutoHideTimer;
790
+ }
791
+ }, autoHideTime);
792
+ this._cancelAutoHideTimer = () => {
793
+ win.clearTimeout(autoHideTimeout);
794
+ delete this._cancelAutoHideTimer;
795
+ };
796
+ }
767
797
  this._intersectionObserver = new IntersectionObserver(([entry]) => {
768
798
  if (entry) {
769
799
  const rect = entry.boundingClientRect;
@@ -782,11 +812,12 @@ var ElementHighlighter = class {
782
812
  this._intersectionObserver.observe(element);
783
813
  }
784
814
  dispose() {
785
- var _a, _b, _c;
815
+ var _a, _b, _c, _d;
786
816
  this._unobserve();
787
817
  (_a = this._cancelScrollTimer) == null ? void 0 : _a.call(this);
788
- (_b = this._window) == null ? void 0 : _b.removeEventListener("scroll", this._onScroll, true);
789
- (_c = this._container) == null ? void 0 : _c.remove();
818
+ (_b = this._cancelAutoHideTimer) == null ? void 0 : _b.call(this);
819
+ (_c = this._window) == null ? void 0 : _c.removeEventListener("scroll", this._onScroll, true);
820
+ (_d = this._container) == null ? void 0 : _d.remove();
790
821
  delete this._element;
791
822
  delete this._container;
792
823
  delete this._window;
@@ -829,10 +860,17 @@ var AccessibilityAffectingElements = {
829
860
  aside: true,
830
861
  body: true,
831
862
  button: true,
863
+ caption: true,
864
+ col: true,
865
+ colgroup: true,
832
866
  datalist: true,
867
+ dd: true,
833
868
  details: true,
834
869
  dialog: true,
835
870
  dl: true,
871
+ dt: true,
872
+ figcaption: true,
873
+ figure: true,
836
874
  form: true,
837
875
  h1: true,
838
876
  h2: true,
@@ -844,6 +882,7 @@ var AccessibilityAffectingElements = {
844
882
  iframe: true,
845
883
  img: true,
846
884
  input: true,
885
+ legend: true,
847
886
  li: true,
848
887
  link: true,
849
888
  main: true,
@@ -853,15 +892,22 @@ var AccessibilityAffectingElements = {
853
892
  nav: true,
854
893
  object: true,
855
894
  ol: true,
895
+ optgroup: true,
856
896
  option: true,
857
897
  progress: true,
858
898
  section: true,
859
899
  select: true,
900
+ source: true,
901
+ summary: true,
902
+ table: true,
860
903
  tbody: true,
904
+ td: true,
861
905
  textarea: true,
862
906
  tfoot: true,
863
907
  th: true,
864
908
  thead: true,
909
+ tr: true,
910
+ track: true,
865
911
  ul: true
866
912
  };
867
913
  var AccessibilityAttributes = {
@@ -994,6 +1040,7 @@ function getStackTrace() {
994
1040
  var AbleDOM = class {
995
1041
  constructor(win, props = {}) {
996
1042
  __publicField(this, "_win");
1043
+ __publicField(this, "_isDisposed", false);
997
1044
  __publicField(this, "_props");
998
1045
  __publicField(this, "_observer");
999
1046
  __publicField(this, "_clearValidationTimeout");
@@ -1006,8 +1053,17 @@ var AbleDOM = class {
1006
1053
  __publicField(this, "_startFunc");
1007
1054
  __publicField(this, "_isStarted", false);
1008
1055
  __publicField(this, "_issuesUI");
1056
+ __publicField(this, "_elementHighlighter");
1009
1057
  __publicField(this, "_idlePromise");
1010
1058
  __publicField(this, "_idleResolve");
1059
+ __publicField(this, "_currentAnchoredIssues", /* @__PURE__ */ new Map());
1060
+ __publicField(this, "_currentNotAnchoredIssues", []);
1061
+ __publicField(this, "_getHighlighter", () => {
1062
+ if (!this._elementHighlighter && !this._isDisposed) {
1063
+ this._elementHighlighter = new ElementHighlighter(this._win);
1064
+ }
1065
+ return this._elementHighlighter;
1066
+ });
1011
1067
  __publicField(this, "_onFocusIn", (event) => {
1012
1068
  var _a;
1013
1069
  const target = event.target;
@@ -1175,9 +1231,9 @@ var AbleDOM = class {
1175
1231
  }
1176
1232
  }
1177
1233
  _addIssue(rule, issue) {
1178
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
1234
+ var _a, _b;
1179
1235
  if (!this._issuesUI) {
1180
- this._issuesUI = new IssuesUI(this._win, {
1236
+ this._issuesUI = new IssuesUI(this._win, this._getHighlighter, {
1181
1237
  bugReport: (_a = this._props) == null ? void 0 : _a.bugReport,
1182
1238
  headless: (_b = this._props) == null ? void 0 : _b.headless
1183
1239
  });
@@ -1203,26 +1259,21 @@ var AbleDOM = class {
1203
1259
  issueUI = new IssueUI(this._win, this, rule, this._issuesUI);
1204
1260
  issues.set(rule, issueUI);
1205
1261
  justUpdate = false;
1206
- (_e = (_d = (_c = this._props) == null ? void 0 : _c.callbacks) == null ? void 0 : _d.onIssueAdded) == null ? void 0 : _e.call(_d, element, rule, issue);
1262
+ this._onIssueAdded(element, rule, issue);
1207
1263
  }
1208
1264
  this._elementsWithIssues.add(element);
1209
1265
  } else {
1210
1266
  issueUI = new IssueUI(this._win, this, rule, this._issuesUI);
1211
1267
  justUpdate = false;
1212
- (_h = (_g = (_f = this._props) == null ? void 0 : _f.callbacks) == null ? void 0 : _g.onIssueAdded) == null ? void 0 : _h.call(_g, null, rule, issue);
1268
+ this._onIssueAdded(null, rule, issue);
1213
1269
  }
1214
1270
  issueUI.update(issue);
1215
- if (justUpdate) {
1216
- (_k = (_j = (_i = this._props) == null ? void 0 : _i.callbacks) == null ? void 0 : _j.onIssueUpdated) == null ? void 0 : _k.call(
1217
- _j,
1218
- rule.anchored && element ? element : null,
1219
- rule,
1220
- issue
1221
- );
1271
+ if (justUpdate && rule.anchored && element) {
1272
+ this._onIssueUpdated(element, rule, issue);
1222
1273
  }
1223
1274
  }
1224
1275
  _removeIssue(element, rule) {
1225
- var _a, _b, _c, _d;
1276
+ var _a;
1226
1277
  if (!rule.anchored) {
1227
1278
  return;
1228
1279
  }
@@ -1234,7 +1285,7 @@ var AbleDOM = class {
1234
1285
  if (issue) {
1235
1286
  issue.dispose();
1236
1287
  issues.delete(rule);
1237
- (_d = (_c = (_b = this._props) == null ? void 0 : _b.callbacks) == null ? void 0 : _c.onIssueRemoved) == null ? void 0 : _d.call(_c, element, rule);
1288
+ this._onIssueRemoved(element, rule);
1238
1289
  }
1239
1290
  if (issues.size === 0) {
1240
1291
  this._elementsWithIssues.delete(element);
@@ -1320,6 +1371,42 @@ var AbleDOM = class {
1320
1371
  this._dependantIdsByElement.set(element, dependsOnIds);
1321
1372
  }
1322
1373
  }
1374
+ _updateCurrentAnchoredIssues(element, rule, issue) {
1375
+ let issuesByElement = this._currentAnchoredIssues.get(element);
1376
+ if (!issuesByElement && issue) {
1377
+ issuesByElement = /* @__PURE__ */ new Map();
1378
+ this._currentAnchoredIssues.set(element, issuesByElement);
1379
+ }
1380
+ if (issuesByElement) {
1381
+ if (issue) {
1382
+ issuesByElement.set(rule, issue);
1383
+ } else {
1384
+ issuesByElement.delete(rule);
1385
+ if (issuesByElement.size === 0) {
1386
+ this._currentAnchoredIssues.delete(element);
1387
+ }
1388
+ }
1389
+ }
1390
+ }
1391
+ _onIssueAdded(element, rule, issue) {
1392
+ var _a, _b, _c;
1393
+ if (element) {
1394
+ this._updateCurrentAnchoredIssues(element, rule, issue);
1395
+ } else {
1396
+ this._currentNotAnchoredIssues.push(issue);
1397
+ }
1398
+ (_c = (_b = (_a = this._props) == null ? void 0 : _a.callbacks) == null ? void 0 : _b.onIssueAdded) == null ? void 0 : _c.call(_b, element, rule, issue);
1399
+ }
1400
+ _onIssueUpdated(element, rule, issue) {
1401
+ var _a, _b, _c;
1402
+ this._updateCurrentAnchoredIssues(element, rule, issue);
1403
+ (_c = (_b = (_a = this._props) == null ? void 0 : _a.callbacks) == null ? void 0 : _b.onIssueUpdated) == null ? void 0 : _c.call(_b, element, rule, issue);
1404
+ }
1405
+ _onIssueRemoved(element, rule) {
1406
+ var _a, _b, _c;
1407
+ this._updateCurrentAnchoredIssues(element, rule, null);
1408
+ (_c = (_b = (_a = this._props) == null ? void 0 : _a.callbacks) == null ? void 0 : _b.onIssueRemoved) == null ? void 0 : _c.call(_b, element, rule);
1409
+ }
1323
1410
  _remove(elements) {
1324
1411
  elements.forEach((element) => {
1325
1412
  var _a, _b;
@@ -1327,21 +1414,42 @@ var AbleDOM = class {
1327
1414
  rules.forEach((rule) => this._removeIssue(element, rule));
1328
1415
  });
1329
1416
  }
1417
+ _getCurrentIssues() {
1418
+ const issues = this._currentNotAnchoredIssues.slice(0);
1419
+ this._currentAnchoredIssues.forEach((issueByRule) => {
1420
+ issueByRule.forEach((issue) => {
1421
+ issues.push(issue);
1422
+ });
1423
+ });
1424
+ return issues;
1425
+ }
1330
1426
  idle() {
1331
1427
  if (!this._clearValidationTimeout) {
1332
- return Promise.resolve();
1428
+ return Promise.resolve(this._getCurrentIssues());
1333
1429
  }
1334
1430
  if (!this._idlePromise) {
1335
1431
  this._idlePromise = new Promise((resolve) => {
1336
1432
  this._idleResolve = () => {
1337
1433
  delete this._idlePromise;
1338
1434
  delete this._idleResolve;
1339
- resolve();
1435
+ resolve(this._getCurrentIssues());
1340
1436
  };
1341
1437
  });
1342
1438
  }
1343
1439
  return this._idlePromise;
1344
1440
  }
1441
+ clearCurrentIssues(anchored = true, notAnchored = true) {
1442
+ if (anchored) {
1443
+ this._currentAnchoredIssues.clear();
1444
+ }
1445
+ if (notAnchored) {
1446
+ this._currentNotAnchoredIssues = [];
1447
+ }
1448
+ }
1449
+ highlightElement(element, scrollIntoView, autoHideTime) {
1450
+ var _a;
1451
+ (_a = this._getHighlighter()) == null ? void 0 : _a.highlight(element, scrollIntoView, autoHideTime);
1452
+ }
1345
1453
  addRule(rule) {
1346
1454
  this._rules.push(rule);
1347
1455
  }
@@ -1368,6 +1476,7 @@ var AbleDOM = class {
1368
1476
  }
1369
1477
  dispose() {
1370
1478
  var _a, _b, _c, _d;
1479
+ this._isDisposed = true;
1371
1480
  const doc = this._win.document;
1372
1481
  doc.addEventListener("focusin", this._onFocusIn, true);
1373
1482
  doc.addEventListener("focusout", this._onFocusOut, true);
@@ -1376,6 +1485,7 @@ var AbleDOM = class {
1376
1485
  this._dependantIdsByElement.clear();
1377
1486
  this._elementsDependingOnId.clear();
1378
1487
  this._idByElement.clear();
1488
+ this.clearCurrentIssues();
1379
1489
  (_a = this._issuesUI) == null ? void 0 : _a.dispose();
1380
1490
  delete this._issuesUI;
1381
1491
  (_b = this._clearValidationTimeout) == null ? void 0 : _b.call(this);
@@ -1967,6 +2077,475 @@ var CustomNotifyRule = class extends ValidationRule {
1967
2077
  });
1968
2078
  }
1969
2079
  };
2080
+
2081
+ // src/rules/requiredparent.ts
2082
+ var RequiredParentRule = class extends ValidationRule {
2083
+ constructor() {
2084
+ super(...arguments);
2085
+ __publicField(this, "type", 1 /* Error */);
2086
+ __publicField(this, "name", "aria-required-parent");
2087
+ __publicField(this, "anchored", true);
2088
+ __publicField(this, "parentRequirements", /* @__PURE__ */ new Map([
2089
+ [
2090
+ "LI",
2091
+ {
2092
+ allowedParents: ["UL", "OL"],
2093
+ allowedParentRoles: ["list"]
2094
+ }
2095
+ ],
2096
+ [
2097
+ "DT",
2098
+ {
2099
+ allowedParents: ["DL"],
2100
+ allowIntermediateWrappers: true,
2101
+ allowedWrappers: ["DIV"]
2102
+ }
2103
+ ],
2104
+ [
2105
+ "DD",
2106
+ {
2107
+ allowedParents: ["DL"],
2108
+ allowIntermediateWrappers: true,
2109
+ allowedWrappers: ["DIV"]
2110
+ }
2111
+ ],
2112
+ [
2113
+ "TR",
2114
+ {
2115
+ allowedParents: ["TABLE", "THEAD", "TBODY", "TFOOT"],
2116
+ allowedParentRoles: ["table", "grid", "treegrid"]
2117
+ }
2118
+ ],
2119
+ [
2120
+ "TH",
2121
+ {
2122
+ allowedParents: ["TR"],
2123
+ allowedParentRoles: ["row"]
2124
+ }
2125
+ ],
2126
+ [
2127
+ "TD",
2128
+ {
2129
+ allowedParents: ["TR"],
2130
+ allowedParentRoles: ["row"]
2131
+ }
2132
+ ],
2133
+ [
2134
+ "THEAD",
2135
+ {
2136
+ allowedParents: ["TABLE"],
2137
+ allowedParentRoles: ["table", "grid", "treegrid"]
2138
+ }
2139
+ ],
2140
+ [
2141
+ "TBODY",
2142
+ {
2143
+ allowedParents: ["TABLE"],
2144
+ allowedParentRoles: ["table", "grid", "treegrid"]
2145
+ }
2146
+ ],
2147
+ [
2148
+ "TFOOT",
2149
+ {
2150
+ allowedParents: ["TABLE"],
2151
+ allowedParentRoles: ["table", "grid", "treegrid"]
2152
+ }
2153
+ ],
2154
+ [
2155
+ "CAPTION",
2156
+ {
2157
+ allowedParents: ["TABLE"]
2158
+ }
2159
+ ],
2160
+ [
2161
+ "COLGROUP",
2162
+ {
2163
+ allowedParents: ["TABLE"]
2164
+ }
2165
+ ],
2166
+ [
2167
+ "COL",
2168
+ {
2169
+ allowedParents: ["COLGROUP"]
2170
+ }
2171
+ ],
2172
+ [
2173
+ "FIGCAPTION",
2174
+ {
2175
+ allowedParents: ["FIGURE"]
2176
+ }
2177
+ ],
2178
+ [
2179
+ "OPTION",
2180
+ {
2181
+ allowedParents: ["SELECT", "OPTGROUP", "DATALIST"]
2182
+ }
2183
+ ],
2184
+ [
2185
+ "OPTGROUP",
2186
+ {
2187
+ allowedParents: ["SELECT"]
2188
+ }
2189
+ ],
2190
+ [
2191
+ "LEGEND",
2192
+ {
2193
+ allowedParents: ["FIELDSET"]
2194
+ }
2195
+ ],
2196
+ [
2197
+ "SUMMARY",
2198
+ {
2199
+ allowedParents: ["DETAILS"]
2200
+ }
2201
+ ],
2202
+ [
2203
+ "SOURCE",
2204
+ {
2205
+ allowedParents: ["AUDIO", "VIDEO", "PICTURE"]
2206
+ }
2207
+ ],
2208
+ [
2209
+ "TRACK",
2210
+ {
2211
+ allowedParents: ["AUDIO", "VIDEO"]
2212
+ }
2213
+ ],
2214
+ [
2215
+ "role=menuitem",
2216
+ {
2217
+ allowedParentRoles: ["menu", "menubar", "group"]
2218
+ }
2219
+ ],
2220
+ [
2221
+ "role=menuitemcheckbox",
2222
+ {
2223
+ allowedParentRoles: ["menu", "menubar", "group"]
2224
+ }
2225
+ ],
2226
+ [
2227
+ "role=menuitemradio",
2228
+ {
2229
+ allowedParentRoles: ["menu", "menubar", "group"]
2230
+ }
2231
+ ],
2232
+ [
2233
+ "role=listitem",
2234
+ {
2235
+ allowedParentRoles: ["list", "group"]
2236
+ }
2237
+ ],
2238
+ [
2239
+ "role=treeitem",
2240
+ {
2241
+ allowedParentRoles: ["tree", "group"]
2242
+ }
2243
+ ],
2244
+ [
2245
+ "role=tab",
2246
+ {
2247
+ allowedParentRoles: ["tablist"]
2248
+ }
2249
+ ],
2250
+ [
2251
+ "role=row",
2252
+ {
2253
+ allowedParentRoles: ["table", "grid", "treegrid", "rowgroup"]
2254
+ }
2255
+ ],
2256
+ [
2257
+ "role=cell",
2258
+ {
2259
+ allowedParentRoles: ["row"]
2260
+ }
2261
+ ],
2262
+ [
2263
+ "role=gridcell",
2264
+ {
2265
+ allowedParentRoles: ["row"]
2266
+ }
2267
+ ],
2268
+ [
2269
+ "role=columnheader",
2270
+ {
2271
+ allowedParentRoles: ["row"]
2272
+ }
2273
+ ],
2274
+ [
2275
+ "role=rowheader",
2276
+ {
2277
+ allowedParentRoles: ["row"]
2278
+ }
2279
+ ],
2280
+ [
2281
+ "role=rowgroup",
2282
+ {
2283
+ allowedParentRoles: ["table", "grid", "treegrid"]
2284
+ }
2285
+ ],
2286
+ [
2287
+ "role=option",
2288
+ {
2289
+ allowedParentRoles: ["listbox", "group"]
2290
+ }
2291
+ ]
2292
+ ]));
2293
+ }
2294
+ accept(element) {
2295
+ const tagName = element.tagName;
2296
+ const role = element.getAttribute("role");
2297
+ if (this.parentRequirements.has(tagName)) {
2298
+ return true;
2299
+ }
2300
+ if (role && this.parentRequirements.has(`role=${role}`)) {
2301
+ return true;
2302
+ }
2303
+ return false;
2304
+ }
2305
+ validate(element) {
2306
+ const tagName = element.tagName;
2307
+ const role = element.getAttribute("role");
2308
+ let requirement;
2309
+ let identifier = "";
2310
+ if (role && this.parentRequirements.has(`role=${role}`)) {
2311
+ requirement = this.parentRequirements.get(`role=${role}`);
2312
+ identifier = `role="${role}"`;
2313
+ } else if (this.parentRequirements.has(tagName)) {
2314
+ requirement = this.parentRequirements.get(tagName);
2315
+ identifier = `<${tagName.toLowerCase()}>`;
2316
+ }
2317
+ if (!requirement) {
2318
+ return null;
2319
+ }
2320
+ if (requirement.customValidator) {
2321
+ if (requirement.customValidator(element)) {
2322
+ return null;
2323
+ } else {
2324
+ return this.createIssue(element, identifier, requirement);
2325
+ }
2326
+ }
2327
+ if (this.hasValidParent(element, requirement)) {
2328
+ return null;
2329
+ }
2330
+ return this.createIssue(element, identifier, requirement);
2331
+ }
2332
+ hasValidParent(element, requirement) {
2333
+ var _a, _b, _c;
2334
+ let parent = element.parentElement;
2335
+ let depth = 0;
2336
+ const maxDepth = requirement.allowIntermediateWrappers ? 2 : 1;
2337
+ while (parent && depth < maxDepth) {
2338
+ if ((_a = requirement.allowedParents) == null ? void 0 : _a.includes(parent.tagName)) {
2339
+ return true;
2340
+ }
2341
+ const parentRole = parent.getAttribute("role");
2342
+ if (parentRole && ((_b = requirement.allowedParentRoles) == null ? void 0 : _b.includes(parentRole))) {
2343
+ return true;
2344
+ }
2345
+ if (depth === 0 && !requirement.allowIntermediateWrappers) {
2346
+ break;
2347
+ }
2348
+ if (depth === 0 && requirement.allowIntermediateWrappers) {
2349
+ if (!((_c = requirement.allowedWrappers) == null ? void 0 : _c.includes(parent.tagName))) {
2350
+ break;
2351
+ }
2352
+ }
2353
+ parent = parent.parentElement;
2354
+ depth++;
2355
+ }
2356
+ return false;
2357
+ }
2358
+ createIssue(element, identifier, requirement) {
2359
+ var _a, _b;
2360
+ const allowedParentsText = [
2361
+ ...((_a = requirement.allowedParents) == null ? void 0 : _a.map((p) => `<${p.toLowerCase()}>`)) || [],
2362
+ ...((_b = requirement.allowedParentRoles) == null ? void 0 : _b.map((r) => `role="${r}"`)) || []
2363
+ ].join(", ");
2364
+ const message = `${identifier} must be contained by ${allowedParentsText}`;
2365
+ return {
2366
+ issue: {
2367
+ id: "aria-required-parent",
2368
+ message,
2369
+ element,
2370
+ help: "https://dequeuniversity.com/rules/axe/4.2/aria-required-parent"
2371
+ }
2372
+ };
2373
+ }
2374
+ };
2375
+
2376
+ // src/rules/nestedInteractive.ts
2377
+ var interactiveElementSelector = [
2378
+ "a[href]",
2379
+ "button",
2380
+ "input:not([type='hidden'])",
2381
+ "select",
2382
+ "textarea",
2383
+ "details",
2384
+ "audio[controls]",
2385
+ "video[controls]",
2386
+ "*[role='button']",
2387
+ "*[role='link']",
2388
+ "*[role='checkbox']",
2389
+ "*[role='radio']",
2390
+ "*[role='switch']",
2391
+ "*[role='tab']",
2392
+ "*[role='menuitem']",
2393
+ "*[role='menuitemcheckbox']",
2394
+ "*[role='menuitemradio']",
2395
+ "*[role='option']",
2396
+ "*[role='treeitem']"
2397
+ ].join(", ");
2398
+ var NestedInteractiveElementRule = class extends ValidationRule {
2399
+ constructor() {
2400
+ super(...arguments);
2401
+ __publicField(this, "type", 1 /* Error */);
2402
+ __publicField(this, "name", "NestedInteractiveElementRule");
2403
+ __publicField(this, "anchored", true);
2404
+ }
2405
+ _isAriaHidden(element) {
2406
+ return element.ownerDocument.evaluate(
2407
+ `ancestor-or-self::*[@aria-hidden = 'true' or @hidden]`,
2408
+ element,
2409
+ null,
2410
+ XPathResult.BOOLEAN_TYPE,
2411
+ null
2412
+ ).booleanValue;
2413
+ }
2414
+ _isInteractive(element) {
2415
+ return matchesSelector(element, interactiveElementSelector);
2416
+ }
2417
+ _findNestedInteractive(element) {
2418
+ const descendants = element.querySelectorAll(interactiveElementSelector);
2419
+ for (let i = 0; i < descendants.length; i++) {
2420
+ const descendant = descendants[i];
2421
+ if (this._isAriaHidden(descendant)) {
2422
+ continue;
2423
+ }
2424
+ return descendant;
2425
+ }
2426
+ return null;
2427
+ }
2428
+ accept(element) {
2429
+ return this._isInteractive(element);
2430
+ }
2431
+ validate(element) {
2432
+ if (this._isAriaHidden(element)) {
2433
+ return null;
2434
+ }
2435
+ const nestedElement = this._findNestedInteractive(element);
2436
+ if (nestedElement) {
2437
+ const elementTag = element.tagName.toLowerCase();
2438
+ const elementRole = element.getAttribute("role");
2439
+ const nestedTag = nestedElement.tagName.toLowerCase();
2440
+ const nestedRole = nestedElement.getAttribute("role");
2441
+ const elementDesc = elementRole ? `${elementTag}[role="${elementRole}"]` : elementTag;
2442
+ const nestedDesc = nestedRole ? `${nestedTag}[role="${nestedRole}"]` : nestedTag;
2443
+ return {
2444
+ issue: isElementVisible(element) ? {
2445
+ id: "nested-interactive",
2446
+ message: `Interactive element <${elementDesc}> contains a nested interactive element <${nestedDesc}>. This can confuse users and assistive technologies.`,
2447
+ element,
2448
+ rel: nestedElement,
2449
+ help: "https://dequeuniversity.com/rules/axe/4.4/nested-interactive"
2450
+ } : void 0
2451
+ };
2452
+ }
2453
+ return null;
2454
+ }
2455
+ };
2456
+
2457
+ // src/rules/tabindex.ts
2458
+ var INTERACTIVE_ELEMENTS = /* @__PURE__ */ new Set([
2459
+ "A",
2460
+ "BUTTON",
2461
+ "INPUT",
2462
+ "SELECT",
2463
+ "TEXTAREA",
2464
+ "DETAILS",
2465
+ "SUMMARY",
2466
+ "AUDIO",
2467
+ "VIDEO"
2468
+ ]);
2469
+ var INTERACTIVE_ROLES = /* @__PURE__ */ new Set([
2470
+ "button",
2471
+ "link",
2472
+ "checkbox",
2473
+ "radio",
2474
+ "textbox",
2475
+ "combobox",
2476
+ "listbox",
2477
+ "menu",
2478
+ "menubar",
2479
+ "menuitem",
2480
+ "menuitemcheckbox",
2481
+ "menuitemradio",
2482
+ "option",
2483
+ "searchbox",
2484
+ "slider",
2485
+ "spinbutton",
2486
+ "switch",
2487
+ "tab",
2488
+ "tablist",
2489
+ "tree",
2490
+ "treegrid",
2491
+ "treeitem",
2492
+ "grid",
2493
+ "gridcell"
2494
+ ]);
2495
+ var TabIndexRule = class extends ValidationRule {
2496
+ constructor() {
2497
+ super(...arguments);
2498
+ __publicField(this, "type", 2 /* Warning */);
2499
+ __publicField(this, "name", "tabindex");
2500
+ __publicField(this, "anchored", true);
2501
+ }
2502
+ accept(element) {
2503
+ return element.hasAttribute("tabindex");
2504
+ }
2505
+ isInteractiveElement(element) {
2506
+ if (INTERACTIVE_ELEMENTS.has(element.tagName)) {
2507
+ if (element.hasAttribute("disabled")) {
2508
+ return false;
2509
+ }
2510
+ if (element.tagName === "A" && !element.hasAttribute("href")) {
2511
+ return false;
2512
+ }
2513
+ return true;
2514
+ }
2515
+ const role = element.getAttribute("role");
2516
+ if (role && INTERACTIVE_ROLES.has(role)) {
2517
+ return true;
2518
+ }
2519
+ if (element.isContentEditable) {
2520
+ return true;
2521
+ }
2522
+ return false;
2523
+ }
2524
+ validate(element) {
2525
+ const tabindex = parseInt(element.getAttribute("tabindex") || "0", 10);
2526
+ if (tabindex > 0 && this.isInteractiveElement(element)) {
2527
+ return {
2528
+ issue: {
2529
+ id: "tabindex",
2530
+ message: `Avoid positive tabindex values (found: ${tabindex})`,
2531
+ element,
2532
+ help: "https://dequeuniversity.com/rules/axe/4.2/tabindex"
2533
+ }
2534
+ };
2535
+ }
2536
+ if (!this.isInteractiveElement(element)) {
2537
+ return {
2538
+ issue: {
2539
+ id: "tabindex-non-interactive",
2540
+ message: `Avoid using tabindex on non-interactive elements (<${element.tagName.toLowerCase()}>). Consider adding an interactive role or making the element naturally interactive.`,
2541
+ element,
2542
+ help: "https://dequeuniversity.com/rules/axe/4.2/tabindex"
2543
+ }
2544
+ };
2545
+ }
2546
+ return null;
2547
+ }
2548
+ };
1970
2549
  export {
1971
2550
  AbleDOM,
1972
2551
  AtomicRule,
@@ -1977,6 +2556,9 @@ export {
1977
2556
  FindElementRule,
1978
2557
  FocusLostRule,
1979
2558
  FocusableElementLabelRule,
2559
+ NestedInteractiveElementRule,
2560
+ RequiredParentRule,
2561
+ TabIndexRule,
1980
2562
  ValidationRule,
1981
2563
  ValidationRuleType,
1982
2564
  hasAccessibilityAttribute,