abledom 0.6.5 → 0.7.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/index.js CHANGED
@@ -56,6 +56,11 @@ var ValidationRule = class {
56
56
  __publicField(this, "_window");
57
57
  __publicField(this, "_exceptions", []);
58
58
  __publicField(this, "_onIssue");
59
+ /**
60
+ * A short friendly group name for grouping issues in the UI.
61
+ * If undefined, the issue will not be grouped.
62
+ */
63
+ __publicField(this, "groupName");
59
64
  }
60
65
  static init(instance, window, onIssue) {
61
66
  instance._window = window;
@@ -100,7 +105,7 @@ var ValidationRule = class {
100
105
  };
101
106
 
102
107
  // inline-file:/Users/marata/tmp/abledom/src/ui/ui.css
103
- 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";
108
+ 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 mix-blend-mode: difference;\n outline: 3px solid red;\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 margin: 2px auto 2px 0;\n padding: 8px 0;\n}\n\n#abledom-report.abledom-align-right .abledom-menu-container {\n margin: 2px 0 2px auto;\n}\n\n.abledom-menu-wrapper {\n backdrop-filter: blur(3px);\n border-radius: 20px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);\n}\n\n.abledom-menu {\n background-color: rgba(140, 10, 121, 0.7);\n border-radius: 20px;\n color: white;\n display: inline flex;\n font-family: Arial, Helvetica, sans-serif;\n font-size: 16px;\n line-height: 26px;\n padding: 6px;\n position: relative;\n}\n\n.abledom-menu .issues-count {\n cursor: pointer;\n display: inline-block;\n margin: 0 8px;\n}\n\n.abledom-menu-container .controls-wrapper {\n display: none;\n left: calc(100% - 28px);\n position: absolute;\n top: -9px;\n}\n\n.abledom-menu .controls-wrapper {\n padding: 8px;\n}\n\n.abledom-menu .controls {\n background: #fff;\n border-radius: 4px;\n border: 1px solid #ddd;\n box-shadow: 0 2px 12px rgba(0, 0, 0, 0.15);\n display: flex;\n margin-left: 30px;\n padding: 6px;\n}\n\n.abledom-menu-container:hover .controls-wrapper {\n display: block;\n}\n\n#abledom-report.abledom-align-right .controls-wrapper {\n left: auto;\n right: calc(100% - 28px);\n}\n\n#abledom-report.abledom-align-right .controls {\n left: auto;\n margin: 0 30px 0 0;\n right: calc(100%);\n}\n\n.abledom-menu .button {\n all: unset;\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 color: #000;\n cursor: pointer;\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-radius: 0;\n border-right-color: rgba(0, 0, 0, 0.4);\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-bottom-left-radius: 6px;\n border-top-left-radius: 6px;\n margin-left: 8px;\n}\n.abledom-menu .align-button-last {\n border-bottom-right-radius: 6px;\n border-right-color: rgba(255, 255, 255, 0.4);\n border-top-right-radius: 6px;\n}\n\n.abledom-issues-container {\n max-height: calc(100vh - 100px);\n overflow: auto;\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-top: 5px;\n}\n\n.abledom-issue-group-issues {\n border-bottom-left-radius: 10px;\n border-left: 3px solid rgba(164, 2, 2, 0.7);\n margin-left: 15px;\n padding-left: 10px;\n}\n\n#abledom-report.abledom-align-right .abledom-issue-group-issues {\n border-bottom-right-radius: 10px;\n border-left: none;\n border-right: 3px solid rgba(164, 2, 2, 0.7);\n margin-left: 0;\n margin-right: 15px;\n padding-left: 0;\n padding-right: 10px;\n}\n\n.abledom-issue_warning + .abledom-issue-group-issues {\n border-left: 3px solid rgba(163, 82, 1, 0.7);\n}\n#abledom-report.abledom-align-right\n .abledom-issue_warning\n + .abledom-issue-group-issues {\n border-right: 3px solid rgba(163, 82, 1, 0.7);\n}\n\n.abledom-issue_info + .abledom-issue-group-issues {\n border-left: 3px solid rgba(0, 0, 255, 0.7);\n}\n#abledom-report.abledom-align-right\n .abledom-issue_info\n + .abledom-issue-group-issues {\n border-right: 3px solid rgba(0, 0, 255, 0.7);\n}\n\n.abledom-issue-group-title {\n background-color: rgba(164, 2, 2, 0.7);\n color: white;\n}\n\n.abledom-issue-group-count {\n font-size: 14px;\n margin: 0 4px;\n opacity: 0.8;\n}\n\n.abledom-issue {\n border-radius: 8px;\n color: #fff;\n display: inline flex;\n font-family: Arial, Helvetica, sans-serif;\n font-size: 16px;\n line-height: 26px;\n padding: 4px;\n text-align: left;\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-group {\n margin: 5px 0 0 0;\n}\n\n.abledom-issue-group-issues .abledom-issue {\n background-color: rgba(198, 198, 198, 0.7);\n border: 1px solid #ccc;\n color: #000;\n}\n\n.abledom-issue-group-issues .abledom-issue .button.close,\n.abledom-issue-group-issues .abledom-issue .button.help {\n color: #000;\n}\n\n.abledom-issue .button {\n all: unset;\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 color: #000;\n cursor: pointer;\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-issue .button.help {\n background: none;\n border-color: transparent;\n color: #fff;\n margin: 0 0 0 2px;\n}\n\n.abledom-issue-group-count {\n background-color: #444;\n border-radius: 10px;\n border: 1px solid black;\n box-sizing: border-box;\n color: #fff;\n display: inline-block;\n height: 20px;\n min-width: 20px;\n padding: 0 5px;\n text-align: center;\n}\n\n.abledom-issue .button.toggle {\n display: flex;\n line-height: 20px;\n}\n\n.abledom-issue .button.toggle svg:nth-child(1) {\n display: none;\n}\n\n.abledom-issue .button.toggle.collapsed svg:nth-child(1) {\n display: inline;\n}\n.abledom-issue .button.toggle.collapsed svg:nth-child(2) {\n display: none;\n}\n";
104
109
 
105
110
  // inline-file:/Users/marata/tmp/abledom/src/ui/highlighter.css
106
111
  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";
@@ -113,27 +118,29 @@ var DOMBuilder = class {
113
118
  this._doc = parent.ownerDocument;
114
119
  this._stack = [parent];
115
120
  }
116
- openTag(tagName, attributes, callback, namespace) {
121
+ openTag(tagName, attributes, callback, namespace, skip) {
117
122
  var _a, _b;
118
123
  const parent = this._stack[0];
119
- const element = namespace ? (_a = this._doc) == null ? void 0 : _a.createElementNS(namespace, tagName) : (_b = this._doc) == null ? void 0 : _b.createElement(tagName);
120
- if (parent && element) {
121
- element.__abledomui = true;
122
- if (attributes) {
123
- for (const [key, value] of Object.entries(attributes)) {
124
- if (key === "class") {
125
- element.className = value;
126
- } else if (key === "style") {
127
- element.style.cssText = value;
128
- } else {
129
- element.setAttribute(key, value);
124
+ const element = skip ? null : namespace ? (_a = this._doc) == null ? void 0 : _a.createElementNS(namespace, tagName) : (_b = this._doc) == null ? void 0 : _b.createElement(tagName);
125
+ if (parent !== void 0) {
126
+ if (parent && element) {
127
+ element.__abledomui = true;
128
+ if (attributes) {
129
+ for (const [key, value] of Object.entries(attributes)) {
130
+ if (key === "class") {
131
+ element.className = value;
132
+ } else if (key === "style") {
133
+ element.style.cssText = value;
134
+ } else {
135
+ element.setAttribute(key, value);
136
+ }
130
137
  }
131
138
  }
139
+ if (callback) {
140
+ callback(element);
141
+ }
142
+ parent.appendChild(element);
132
143
  }
133
- if (callback) {
134
- callback(element);
135
- }
136
- parent.appendChild(element);
137
144
  this._stack.unshift(element);
138
145
  }
139
146
  return this;
@@ -155,7 +162,8 @@ var DOMBuilder = class {
155
162
  return this;
156
163
  }
157
164
  element(callback) {
158
- callback(this._stack[0]);
165
+ const el = this._stack[0];
166
+ el && callback(el);
159
167
  return this;
160
168
  }
161
169
  };
@@ -328,8 +336,31 @@ var alignbottomleft_default = (function buildSVG12(parent) {
328
336
  return parent.firstElementChild;
329
337
  });
330
338
 
339
+ // inline-file:/Users/marata/tmp/abledom/src/ui/chevrondown.svg
340
+ var chevrondown_default = (function buildSVG13(parent) {
341
+ const builder = new DOMBuilder(parent);
342
+ builder.openTag("svg", { "width": "20", "height": "20", "viewBox": "0 0 24 24", "fill": "none", "stroke": "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "xmlns": "http://www.w3.org/2000/svg" }, void 0, "http://www.w3.org/2000/svg");
343
+ builder.openTag("polyline", { "points": "6 9 12 15 18 9" }, void 0, "http://www.w3.org/2000/svg");
344
+ builder.closeTag();
345
+ builder.closeTag();
346
+ return parent.firstElementChild;
347
+ });
348
+
349
+ // inline-file:/Users/marata/tmp/abledom/src/ui/chevronright.svg
350
+ var chevronright_default = (function buildSVG14(parent) {
351
+ const builder = new DOMBuilder(parent);
352
+ builder.openTag("svg", { "width": "20", "height": "20", "viewBox": "0 0 24 24", "fill": "none", "stroke": "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "xmlns": "http://www.w3.org/2000/svg" }, void 0, "http://www.w3.org/2000/svg");
353
+ builder.openTag("polyline", { "points": "9 6 15 12 9 18" }, void 0, "http://www.w3.org/2000/svg");
354
+ builder.closeTag();
355
+ builder.closeTag();
356
+ return parent.firstElementChild;
357
+ });
358
+
331
359
  // src/ui/ui.ts
332
360
  var pressedClass = "pressed";
361
+ function getIssueTypeClass(type) {
362
+ return type === 2 /* Warning */ ? " abledom-issue_warning" : type === 3 /* Info */ ? " abledom-issue_info" : "";
363
+ }
333
364
  var IssueUI = class {
334
365
  constructor(win, core, rule, issuesUI) {
335
366
  __publicField(this, "_core");
@@ -337,6 +368,7 @@ var IssueUI = class {
337
368
  __publicField(this, "_wrapper");
338
369
  __publicField(this, "_rule");
339
370
  __publicField(this, "_onToggle");
371
+ __publicField(this, "_appended", false);
340
372
  __publicField(this, "isHidden", false);
341
373
  this._core = core;
342
374
  this._rule = rule;
@@ -345,35 +377,62 @@ var IssueUI = class {
345
377
  this._wrapper = win.document.createElement(
346
378
  "div"
347
379
  );
380
+ this._wrapper.__ableDOMIssueUI = this;
381
+ this._wrapper.className = "abledom-issue-container-wrapper";
348
382
  }
349
383
  issuesUI.addIssue(this);
350
384
  }
351
385
  static setOnToggle(instance, onToggle) {
352
386
  instance._onToggle = onToggle;
353
387
  }
354
- static getElement(instance) {
355
- return instance._wrapper;
388
+ static setAppended(instance) {
389
+ instance._appended = true;
356
390
  }
357
391
  update(issue) {
358
- const rule = this._rule;
359
392
  const wrapper = this._wrapper;
360
- const element = issue.element;
361
393
  if (!wrapper) {
362
394
  return;
363
395
  }
396
+ this._appendToIssueContainer(issue);
364
397
  wrapper.__abledomui = true;
365
398
  wrapper.textContent = "";
399
+ this._renderIssueContent(wrapper, issue);
400
+ }
401
+ _appendToIssueContainer(issue) {
402
+ var _a, _b, _c;
403
+ if (!this._appended) {
404
+ return;
405
+ }
406
+ const wrapper = this._wrapper;
407
+ const rule = this._rule;
408
+ if (!wrapper) {
409
+ return;
410
+ }
411
+ const issueContainer = (_a = this._issuesUI) == null ? void 0 : _a.getIssueContainer(
412
+ rule.type,
413
+ rule.groupName,
414
+ issue.help
415
+ );
416
+ if (!issueContainer || wrapper.parentElement === issueContainer) {
417
+ return;
418
+ }
419
+ issueContainer.appendChild(wrapper);
420
+ if (!this.isHidden) {
421
+ if ((_b = issueContainer.parentElement) == null ? void 0 : _b.classList.contains("abledom-issue-group")) {
422
+ issueContainer.parentElement.style.display = "block";
423
+ }
424
+ } else {
425
+ this.toggle(false, true);
426
+ }
427
+ (_c = this._issuesUI) == null ? void 0 : _c.syncGroupIssueCounts();
428
+ }
429
+ _renderIssueContent(wrapper, issue) {
430
+ const rule = this._rule;
431
+ const element = issue.element;
366
432
  new DOMBuilder(wrapper).openTag("div", { class: "abledom-issue-container" }, (container) => {
367
- container.onmouseenter = () => {
368
- var _a;
369
- element && ((_a = this._issuesUI) == null ? void 0 : _a.highlight(element));
370
- };
371
- container.onmouseleave = () => {
372
- var _a;
373
- (_a = this._issuesUI) == null ? void 0 : _a.highlight(null);
374
- };
433
+ this._bindIssueContainerHover(container, element);
375
434
  }).openTag("div", {
376
- class: `abledom-issue${rule.type === 2 /* Warning */ ? " abledom-issue_warning" : rule.type === 3 /* Info */ ? " abledom-issue_info" : ""}`
435
+ class: `abledom-issue${getIssueTypeClass(rule.type)}`
377
436
  }).openTag(
378
437
  "button",
379
438
  {
@@ -381,21 +440,7 @@ var IssueUI = class {
381
440
  title: "Log to Console"
382
441
  },
383
442
  (logButton) => {
384
- logButton.onclick = () => {
385
- const { id, message, element: element2, rel, help, ...extra } = issue;
386
- this._core.log(
387
- "AbleDOM: ",
388
- "\nid:",
389
- id,
390
- "\nmessage:",
391
- message,
392
- "\nelement:",
393
- element2,
394
- ...rel ? ["\nrelative:", rel] : [],
395
- ...help ? ["\nhelp:", help] : [],
396
- ...Object.keys(extra).length > 0 ? ["\nextra:", extra] : []
397
- );
398
- };
443
+ this._bindLogButton(logButton, issue);
399
444
  }
400
445
  ).element(log_default).closeTag().openTag(
401
446
  "button",
@@ -405,16 +450,10 @@ var IssueUI = class {
405
450
  title: "Scroll element into view"
406
451
  },
407
452
  (revealButton) => {
408
- const element2 = issue.element;
409
- if (element2) {
410
- revealButton.onclick = () => {
411
- var _a;
412
- (_a = this._issuesUI) == null ? void 0 : _a.highlight(element2, true);
413
- };
414
- } else {
415
- revealButton.style.display = "none";
416
- }
417
- }
453
+ this._bindRevealButton(revealButton, issue);
454
+ },
455
+ void 0,
456
+ !issue.element
418
457
  ).element(reveal_default).closeTag().openTag(
419
458
  "button",
420
459
  {
@@ -422,33 +461,21 @@ var IssueUI = class {
422
461
  title: "Report bug"
423
462
  },
424
463
  (bugReportButton) => {
425
- var _a, _b;
426
- const bugReport = (_a = this._issuesUI) == null ? void 0 : _a.bugReport;
427
- if (bugReport == null ? void 0 : bugReport.isVisible(issue)) {
428
- const title = (_b = bugReport.getTitle) == null ? void 0 : _b.call(bugReport, issue);
429
- if (title) {
430
- bugReportButton.title = title;
431
- }
432
- bugReportButton.onclick = () => {
433
- bugReport.onClick(issue);
434
- };
435
- } else {
436
- bugReportButton.style.display = "none";
437
- }
464
+ this._bindBugReportButton(bugReportButton, issue);
438
465
  }
439
466
  ).element(bug_default).closeTag().text(issue.message).openTag(
440
467
  "a",
441
468
  {
442
- class: "button close",
469
+ class: "button help",
443
470
  href: issue.help || "/",
444
471
  title: "Open help",
445
472
  target: "_blank"
446
473
  },
447
474
  (help) => {
448
- if (!issue.help) {
449
- help.style.display = "none";
450
- }
451
- }
475
+ this._bindHelpLink(help, issue.help);
476
+ },
477
+ void 0,
478
+ !!rule.groupName
452
479
  ).element(help_default).closeTag().openTag(
453
480
  "button",
454
481
  {
@@ -456,27 +483,116 @@ var IssueUI = class {
456
483
  title: "Hide"
457
484
  },
458
485
  (closeButton) => {
459
- closeButton.onclick = () => {
460
- var _a;
461
- this.toggle(false);
462
- (_a = this._issuesUI) == null ? void 0 : _a.highlight(null);
463
- };
486
+ this._bindCloseButton(closeButton);
464
487
  }
465
488
  ).element(close_default).closeTag().closeTag().closeTag();
466
489
  }
490
+ _bindIssueContainerHover(container, element) {
491
+ container.onmouseenter = () => {
492
+ var _a;
493
+ element && ((_a = this._issuesUI) == null ? void 0 : _a.highlight(element));
494
+ };
495
+ container.onmouseleave = () => {
496
+ var _a;
497
+ (_a = this._issuesUI) == null ? void 0 : _a.highlight(null);
498
+ };
499
+ }
500
+ _bindLogButton(button, issue) {
501
+ button.onclick = () => {
502
+ const { id, message, element, rel, help, ...extra } = issue;
503
+ this._core.log(
504
+ "AbleDOM: ",
505
+ "\nid:",
506
+ id,
507
+ "\nmessage:",
508
+ message,
509
+ "\nelement:",
510
+ element,
511
+ ...rel ? ["\nrelative:", rel] : [],
512
+ ...help ? ["\nhelp:", help] : [],
513
+ ...Object.keys(extra).length > 0 ? ["\nextra:", extra] : []
514
+ );
515
+ };
516
+ }
517
+ _bindRevealButton(button, issue) {
518
+ const element = issue.element;
519
+ if (element) {
520
+ button.onclick = () => {
521
+ var _a;
522
+ (_a = this._issuesUI) == null ? void 0 : _a.highlight(element, true);
523
+ };
524
+ }
525
+ }
526
+ _bindBugReportButton(button, issue) {
527
+ var _a, _b;
528
+ const bugReport = (_a = this._issuesUI) == null ? void 0 : _a.bugReport;
529
+ if (bugReport == null ? void 0 : bugReport.isVisible(issue)) {
530
+ const title = (_b = bugReport.getTitle) == null ? void 0 : _b.call(bugReport, issue);
531
+ if (title) {
532
+ button.title = title;
533
+ }
534
+ button.onclick = () => {
535
+ bugReport.onClick(issue);
536
+ };
537
+ } else {
538
+ button.style.display = "none";
539
+ }
540
+ }
541
+ _bindHelpLink(help, issueHelp) {
542
+ if (!issueHelp) {
543
+ help.style.display = "none";
544
+ }
545
+ }
546
+ _bindCloseButton(button) {
547
+ button.onclick = () => {
548
+ var _a;
549
+ this.toggle(false);
550
+ (_a = this._issuesUI) == null ? void 0 : _a.highlight(null);
551
+ };
552
+ }
467
553
  toggle(show, initial = false) {
468
554
  var _a;
469
555
  if (!this._wrapper) {
470
556
  return;
471
557
  }
472
- this.isHidden = !show;
558
+ if (show === void 0) {
559
+ this.isHidden = !this.isHidden;
560
+ show = !this.isHidden;
561
+ } else {
562
+ this.isHidden = !show;
563
+ }
473
564
  if (!initial) {
474
- (_a = this._onToggle) == null ? void 0 : _a.call(this, this, show);
475
- if (!this._rule.anchored && !show) {
565
+ (_a = this._onToggle) == null ? void 0 : _a.call(this, this, !this.isHidden);
566
+ if (!this._rule.anchored && this.isHidden) {
476
567
  this.dispose();
477
568
  }
478
569
  }
479
570
  this._wrapper.style.display = show ? "block" : "none";
571
+ this._syncGroupVisibility(!!show);
572
+ }
573
+ _syncGroupVisibility(show) {
574
+ const wrapper = this._wrapper;
575
+ if (!wrapper) {
576
+ return;
577
+ }
578
+ const potentiallyGroupIssuesElement = wrapper.parentElement;
579
+ const potentiallyGroupElement = potentiallyGroupIssuesElement == null ? void 0 : potentiallyGroupIssuesElement.parentElement;
580
+ if (!potentiallyGroupIssuesElement || !(potentiallyGroupElement == null ? void 0 : potentiallyGroupElement.classList.contains("abledom-issue-group"))) {
581
+ return;
582
+ }
583
+ if (show) {
584
+ potentiallyGroupElement.style.display = "block";
585
+ return;
586
+ }
587
+ if (potentiallyGroupElement.style.display !== "none" && Array.prototype.every.call(
588
+ potentiallyGroupIssuesElement.children,
589
+ (el) => {
590
+ var _a;
591
+ return el.__ableDOMIssueUI ? (_a = el.__ableDOMIssueUI) == null ? void 0 : _a.isHidden : true;
592
+ }
593
+ )) {
594
+ potentiallyGroupElement.style.display = "none";
595
+ }
480
596
  }
481
597
  dispose() {
482
598
  var _a, _b;
@@ -500,6 +616,8 @@ var IssuesUI = class {
500
616
  __publicField(this, "_alignBottomRightButton");
501
617
  __publicField(this, "_isMuted", false);
502
618
  __publicField(this, "_issues", /* @__PURE__ */ new Set());
619
+ __publicField(this, "_issueGroupContainers", {});
620
+ __publicField(this, "_issueGroupCountElements", {});
503
621
  __publicField(this, "_getHighlighter");
504
622
  __publicField(this, "bugReport");
505
623
  __publicField(this, "headless");
@@ -511,31 +629,54 @@ var IssuesUI = class {
511
629
  return;
512
630
  }
513
631
  const doc = win.document;
514
- const container = this._container = doc.createElement("div");
632
+ const container = this._container = this._createRootContainer(doc);
633
+ this._issuesContainer = this._createIssuesContainer(doc, container);
634
+ const menuElement = this._menuElement = this._createMenuContainer(
635
+ doc,
636
+ container
637
+ );
638
+ this._buildMenu(menuElement);
639
+ doc.body.appendChild(container);
640
+ }
641
+ _createRootContainer(doc) {
642
+ const container = doc.createElement("div");
515
643
  container.__abledomui = true;
516
644
  container.id = "abledom-report";
517
645
  const style = doc.createElement("style");
518
646
  style.type = "text/css";
519
647
  style.appendChild(doc.createTextNode(ui_default));
520
648
  container.appendChild(style);
521
- const issuesContainer = this._issuesContainer = doc.createElement("div");
649
+ return container;
650
+ }
651
+ _createIssuesContainer(doc, container) {
652
+ const issuesContainer = doc.createElement(
653
+ "div"
654
+ );
522
655
  issuesContainer.__abledomui = true;
523
656
  issuesContainer.className = "abledom-issues-container";
524
657
  container.appendChild(issuesContainer);
525
- const menuElement = this._menuElement = doc.createElement("div");
658
+ return issuesContainer;
659
+ }
660
+ _createMenuContainer(doc, container) {
661
+ const menuElement = doc.createElement(
662
+ "div"
663
+ );
526
664
  menuElement.__abledomui = true;
527
665
  menuElement.className = "abledom-menu-container";
528
666
  container.appendChild(menuElement);
529
- new DOMBuilder(menuElement).openTag("div", { class: "abledom-menu" }).openTag(
667
+ return menuElement;
668
+ }
669
+ _buildMenu(menuElement) {
670
+ new DOMBuilder(menuElement).openTag("div", { class: "abledom-menu-wrapper" }).openTag("div", { class: "abledom-menu" }).openTag(
530
671
  "span",
531
672
  {
532
673
  class: "issues-count",
533
674
  title: "Number of issues"
534
675
  },
535
676
  (issueCountElement) => {
536
- this._issueCountElement = issueCountElement;
677
+ this._bindIssueCountElement(issueCountElement);
537
678
  }
538
- ).closeTag().openTag(
679
+ ).closeTag().openTag("div", { class: "controls-wrapper" }).openTag("div", { class: "controls" }).openTag(
539
680
  "button",
540
681
  {
541
682
  class: "button",
@@ -543,9 +684,7 @@ var IssuesUI = class {
543
684
  },
544
685
  (showAllButton) => {
545
686
  this._showAllButton = showAllButton;
546
- showAllButton.onclick = () => {
547
- this.showAll();
548
- };
687
+ this._bindToggleAllButton(showAllButton, true);
549
688
  }
550
689
  ).element(showall_default).closeTag().openTag(
551
690
  "button",
@@ -555,9 +694,7 @@ var IssuesUI = class {
555
694
  },
556
695
  (hideAllButton) => {
557
696
  this._hideAllButton = hideAllButton;
558
- hideAllButton.onclick = () => {
559
- this.hideAll();
560
- };
697
+ this._bindToggleAllButton(hideAllButton, false);
561
698
  }
562
699
  ).element(hideall_default).closeTag().openTag(
563
700
  "button",
@@ -566,14 +703,7 @@ var IssuesUI = class {
566
703
  title: "Mute newly appearing issues"
567
704
  },
568
705
  (muteButton) => {
569
- muteButton.onclick = () => {
570
- const isMuted = this._isMuted = muteButton.classList.toggle(pressedClass);
571
- if (isMuted) {
572
- muteButton.setAttribute("title", "Unmute newly appearing issues");
573
- } else {
574
- muteButton.setAttribute("title", "Mute newly appearing issues");
575
- }
576
- };
706
+ this._bindMuteButton(muteButton);
577
707
  }
578
708
  ).element(muteall_default).closeTag().openTag(
579
709
  "button",
@@ -583,9 +713,10 @@ var IssuesUI = class {
583
713
  },
584
714
  (alignBottomLeftButton) => {
585
715
  this._alignBottomLeftButton = alignBottomLeftButton;
586
- alignBottomLeftButton.onclick = () => {
587
- this.setUIAlignment("bottom-left" /* BottomLeft */);
588
- };
716
+ this._bindAlignmentButton(
717
+ alignBottomLeftButton,
718
+ "bottom-left" /* BottomLeft */
719
+ );
589
720
  }
590
721
  ).element(alignbottomleft_default).closeTag().openTag(
591
722
  "button",
@@ -595,9 +726,7 @@ var IssuesUI = class {
595
726
  },
596
727
  (alignTopLeftButton) => {
597
728
  this._alignTopLeftButton = alignTopLeftButton;
598
- alignTopLeftButton.onclick = () => {
599
- this.setUIAlignment("top-left" /* TopLeft */);
600
- };
729
+ this._bindAlignmentButton(alignTopLeftButton, "top-left" /* TopLeft */);
601
730
  }
602
731
  ).element(aligntopleft_default).closeTag().openTag(
603
732
  "button",
@@ -607,9 +736,7 @@ var IssuesUI = class {
607
736
  },
608
737
  (alignTopRightButton) => {
609
738
  this._alignTopRightButton = alignTopRightButton;
610
- alignTopRightButton.onclick = () => {
611
- this.setUIAlignment("top-right" /* TopRight */);
612
- };
739
+ this._bindAlignmentButton(alignTopRightButton, "top-right" /* TopRight */);
613
740
  }
614
741
  ).element(aligntopright_default).closeTag().openTag(
615
742
  "button",
@@ -619,55 +746,89 @@ var IssuesUI = class {
619
746
  },
620
747
  (alignBottomRightButton) => {
621
748
  this._alignBottomRightButton = alignBottomRightButton;
622
- alignBottomRightButton.onclick = () => {
623
- this.setUIAlignment("bottom-right" /* BottomRight */);
624
- };
749
+ this._bindAlignmentButton(
750
+ alignBottomRightButton,
751
+ "bottom-right" /* BottomRight */
752
+ );
625
753
  }
626
- ).element(alignbottomright_default).closeTag().closeTag();
627
- doc.body.appendChild(container);
754
+ ).element(alignbottomright_default).closeTag().closeTag().closeTag().closeTag().closeTag();
755
+ }
756
+ _bindToggleAllButton(button, show) {
757
+ button.onclick = () => {
758
+ this.toggleAll(show);
759
+ };
760
+ }
761
+ _bindIssueCountElement(element) {
762
+ this._issueCountElement = element;
763
+ element.onclick = () => {
764
+ this.toggleAll();
765
+ };
766
+ }
767
+ _bindMuteButton(button) {
768
+ button.onclick = () => {
769
+ const isMuted = this._isMuted = button.classList.toggle(pressedClass);
770
+ button.setAttribute(
771
+ "title",
772
+ isMuted ? "Unmute newly appearing issues" : "Mute newly appearing issues"
773
+ );
774
+ };
775
+ }
776
+ _bindAlignmentButton(button, alignment) {
777
+ button.onclick = () => {
778
+ this.setUIAlignment(alignment);
779
+ };
628
780
  }
629
781
  setUIAlignment(alignment) {
630
- var _a, _b, _c, _d, _e, _f, _g, _h;
631
782
  if (!this._container || !this._issuesContainer || !this._menuElement) {
632
783
  return;
633
784
  }
634
- (_a = this._alignBottomLeftButton) == null ? void 0 : _a.classList.remove(pressedClass);
635
- (_b = this._alignBottomRightButton) == null ? void 0 : _b.classList.remove(pressedClass);
636
- (_c = this._alignTopLeftButton) == null ? void 0 : _c.classList.remove(pressedClass);
637
- (_d = this._alignTopRightButton) == null ? void 0 : _d.classList.remove(pressedClass);
785
+ this._clearAlignmentButtons();
638
786
  this._container.classList.remove(
639
787
  "abledom-align-left",
640
788
  "abledom-align-right",
641
789
  "abledom-align-top",
642
790
  "abledom-align-bottom"
643
791
  );
792
+ const { containerClasses, issuesFirst, activeButton } = this._getAlignmentLayout(alignment);
793
+ activeButton == null ? void 0 : activeButton.classList.add(pressedClass);
794
+ this._container.classList.add(...containerClasses);
795
+ this._container.insertBefore(
796
+ this._issuesContainer,
797
+ issuesFirst ? this._menuElement : null
798
+ );
799
+ }
800
+ _clearAlignmentButtons() {
801
+ var _a, _b, _c, _d;
802
+ (_a = this._alignBottomLeftButton) == null ? void 0 : _a.classList.remove(pressedClass);
803
+ (_b = this._alignBottomRightButton) == null ? void 0 : _b.classList.remove(pressedClass);
804
+ (_c = this._alignTopLeftButton) == null ? void 0 : _c.classList.remove(pressedClass);
805
+ (_d = this._alignTopRightButton) == null ? void 0 : _d.classList.remove(pressedClass);
806
+ }
807
+ _getAlignmentLayout(alignment) {
644
808
  let containerClasses = [];
645
809
  let issuesFirst = false;
810
+ let activeButton;
646
811
  switch (alignment) {
647
812
  case "bottom-left" /* BottomLeft */:
648
813
  containerClasses = ["abledom-align-left", "abledom-align-bottom"];
649
814
  issuesFirst = true;
650
- (_e = this._alignBottomLeftButton) == null ? void 0 : _e.classList.add(pressedClass);
815
+ activeButton = this._alignBottomLeftButton;
651
816
  break;
652
817
  case "bottom-right" /* BottomRight */:
653
818
  containerClasses = ["abledom-align-right", "abledom-align-bottom"];
654
819
  issuesFirst = true;
655
- (_f = this._alignBottomRightButton) == null ? void 0 : _f.classList.add(pressedClass);
820
+ activeButton = this._alignBottomRightButton;
656
821
  break;
657
822
  case "top-left" /* TopLeft */:
658
823
  containerClasses = ["abledom-align-left", "abledom-align-top"];
659
- (_g = this._alignTopLeftButton) == null ? void 0 : _g.classList.add(pressedClass);
824
+ activeButton = this._alignTopLeftButton;
660
825
  break;
661
826
  case "top-right" /* TopRight */:
662
827
  containerClasses = ["abledom-align-right", "abledom-align-top"];
663
- (_h = this._alignTopRightButton) == null ? void 0 : _h.classList.add(pressedClass);
828
+ activeButton = this._alignTopRightButton;
664
829
  break;
665
830
  }
666
- this._container.classList.add(...containerClasses);
667
- this._container.insertBefore(
668
- this._issuesContainer,
669
- issuesFirst ? this._menuElement : null
670
- );
831
+ return { containerClasses, issuesFirst, activeButton };
671
832
  }
672
833
  _setIssuesCount(count) {
673
834
  if (!this._menuElement) {
@@ -675,11 +836,19 @@ var IssuesUI = class {
675
836
  }
676
837
  const countElement = this._issueCountElement;
677
838
  if (countElement && count > 0) {
678
- countElement.textContent = "";
679
- new DOMBuilder(countElement).openTag("strong").text(`${count}`).closeTag().text(` issue${count > 1 ? "s" : ""}`);
680
- this._menuElement.style.display = "block";
839
+ this._renderIssueCountText(countElement, count);
840
+ this._setMenuVisibility(true);
681
841
  } else {
682
- this._menuElement.style.display = "none";
842
+ this._setMenuVisibility(false);
843
+ }
844
+ }
845
+ _renderIssueCountText(countElement, count) {
846
+ countElement.textContent = "";
847
+ new DOMBuilder(countElement).openTag("strong").text(`${count}`).closeTag().text(` issue${count > 1 ? "s" : ""}`);
848
+ }
849
+ _setMenuVisibility(visible) {
850
+ if (this._menuElement) {
851
+ this._menuElement.style.display = visible ? "block" : "none";
683
852
  }
684
853
  }
685
854
  _setShowHideButtonsVisibility() {
@@ -688,9 +857,14 @@ var IssuesUI = class {
688
857
  if (!showAllButton || !hideAllButton) {
689
858
  return;
690
859
  }
860
+ const { allHidden, allVisible } = this._getIssueVisibilityState();
861
+ hideAllButton.style.display = allHidden ? "none" : "";
862
+ showAllButton.style.display = allVisible ? "none" : "";
863
+ }
864
+ _getIssueVisibilityState() {
691
865
  let allHidden = true;
692
866
  let allVisible = true;
693
- for (let issue of this._issues) {
867
+ for (const issue of this._issues) {
694
868
  if (issue.isHidden) {
695
869
  allVisible = false;
696
870
  } else {
@@ -700,8 +874,11 @@ var IssuesUI = class {
700
874
  break;
701
875
  }
702
876
  }
703
- hideAllButton.style.display = allHidden ? "none" : "block";
704
- showAllButton.style.display = allVisible ? "none" : "block";
877
+ return { allHidden, allVisible };
878
+ }
879
+ _syncMenuState() {
880
+ this._setIssuesCount(this._issues.size);
881
+ this._setShowHideButtonsVisibility();
705
882
  }
706
883
  addIssue(issue) {
707
884
  if (this._issues.has(issue)) {
@@ -717,32 +894,148 @@ var IssuesUI = class {
717
894
  if (this._isMuted) {
718
895
  issue.toggle(false, true);
719
896
  }
720
- const issueUIWraper = IssueUI.getElement(issue);
721
- issueUIWraper && this._issuesContainer.appendChild(issueUIWraper);
897
+ IssueUI.setAppended(issue);
722
898
  IssueUI.setOnToggle(issue, () => {
723
899
  this._setShowHideButtonsVisibility();
724
900
  });
725
- this._setIssuesCount(this._issues.size);
726
- this._setShowHideButtonsVisibility();
901
+ this._syncMenuState();
902
+ }
903
+ getIssueContainer(type, groupName, helpLink) {
904
+ if (!this._issuesContainer) {
905
+ throw new Error("IssuesUI is not initialized");
906
+ }
907
+ if (!groupName) {
908
+ return this._issuesContainer;
909
+ }
910
+ let groupContainer = this._issueGroupContainers[groupName];
911
+ if (!groupContainer) {
912
+ groupContainer = this._createIssueGroup(groupName, type, helpLink);
913
+ }
914
+ return groupContainer;
915
+ }
916
+ syncGroupIssueCounts() {
917
+ this._updateGroupIssueCounts();
918
+ }
919
+ _createIssueGroup(groupName, type, helpLink) {
920
+ if (!this._issuesContainer) {
921
+ throw new Error("IssuesUI is not initialized");
922
+ }
923
+ let groupContainer;
924
+ new DOMBuilder(this._issuesContainer).openTag("div", { class: "abledom-issue-group" }).openTag("div", {
925
+ class: `abledom-issue-group-title abledom-issue${getIssueTypeClass(type)}`
926
+ }).openTag(
927
+ "button",
928
+ {
929
+ class: "button toggle collapsed",
930
+ title: "Toggle group"
931
+ },
932
+ (toggleButton) => {
933
+ this._bindGroupToggleButton(toggleButton, () => groupContainer);
934
+ }
935
+ ).element(chevronright_default).element(chevrondown_default).openTag("span", { class: "abledom-issue-group-count" }, (countEl) => {
936
+ this._issueGroupCountElements[groupName] = countEl;
937
+ }).closeTag().closeTag().text(groupName).openTag(
938
+ "a",
939
+ {
940
+ class: "button help",
941
+ href: helpLink || "/",
942
+ title: "Open help",
943
+ target: "_blank"
944
+ },
945
+ (help) => {
946
+ this._hideHelpLinkIfMissing(help, helpLink);
947
+ }
948
+ ).element(help_default).closeTag().openTag(
949
+ "button",
950
+ {
951
+ class: "button close",
952
+ title: "Hide"
953
+ },
954
+ (closeButton) => {
955
+ this._bindGroupCloseButton(closeButton, () => groupContainer);
956
+ }
957
+ ).element(close_default).closeTag().closeTag().openTag("div", { class: "abledom-issue-group-issues" }, (element) => {
958
+ this._issueGroupContainers[groupName] = groupContainer = element;
959
+ groupContainer.style.display = "none";
960
+ }).closeTag().closeTag();
961
+ if (!groupContainer) {
962
+ throw new Error("Issue group container was not created");
963
+ }
964
+ return groupContainer;
965
+ }
966
+ _bindGroupToggleButton(button, getGroupContainer) {
967
+ let isCollapsed = true;
968
+ button.onclick = () => {
969
+ isCollapsed = !isCollapsed;
970
+ button.classList.toggle("collapsed", isCollapsed);
971
+ const groupContainer = getGroupContainer();
972
+ if (groupContainer) {
973
+ groupContainer.style.display = isCollapsed ? "none" : "";
974
+ }
975
+ };
976
+ }
977
+ _bindGroupCloseButton(button, getGroupContainer) {
978
+ button.onclick = () => {
979
+ const groupContainer = getGroupContainer();
980
+ if (groupContainer) {
981
+ Array.prototype.forEach.call(
982
+ groupContainer.children,
983
+ (el) => {
984
+ var _a;
985
+ (_a = el.__ableDOMIssueUI) == null ? void 0 : _a.toggle(false);
986
+ }
987
+ );
988
+ this._setShowHideButtonsVisibility();
989
+ }
990
+ this.highlight(null);
991
+ };
992
+ }
993
+ _hideHelpLinkIfMissing(help, helpLink) {
994
+ if (!helpLink) {
995
+ help.style.display = "none";
996
+ }
997
+ }
998
+ _updateGroupIssueCounts() {
999
+ for (const [groupName, container] of Object.entries(
1000
+ this._issueGroupContainers
1001
+ )) {
1002
+ const countElement = this._issueGroupCountElements[groupName];
1003
+ if (container && countElement) {
1004
+ const count = container.children.length;
1005
+ if (count === 0) {
1006
+ this._removeIssueGroup(groupName, container);
1007
+ continue;
1008
+ }
1009
+ countElement.textContent = `${count}`;
1010
+ }
1011
+ }
1012
+ }
1013
+ _removeIssueGroup(groupName, container) {
1014
+ const groupElement = container.parentElement;
1015
+ if (groupElement == null ? void 0 : groupElement.classList.contains("abledom-issue-group")) {
1016
+ groupElement.remove();
1017
+ } else {
1018
+ container.remove();
1019
+ }
1020
+ delete this._issueGroupContainers[groupName];
1021
+ delete this._issueGroupCountElements[groupName];
727
1022
  }
728
1023
  removeIssue(issue) {
729
1024
  if (!this._issues.has(issue)) {
730
1025
  return;
731
1026
  }
732
1027
  this._issues.delete(issue);
733
- this._setIssuesCount(this._issues.size);
734
- this._setShowHideButtonsVisibility();
1028
+ this._syncMenuState();
1029
+ this._updateGroupIssueCounts();
735
1030
  this.highlight(null);
736
1031
  }
737
- hideAll() {
738
- this._issues.forEach((issue) => {
739
- issue.toggle(false);
740
- });
741
- this._setShowHideButtonsVisibility();
742
- }
743
- showAll() {
1032
+ toggleAll(show) {
1033
+ if (show === void 0) {
1034
+ const { allVisible } = this._getIssueVisibilityState();
1035
+ show = !allVisible;
1036
+ }
744
1037
  this._issues.forEach((issue) => {
745
- issue.toggle(true);
1038
+ issue.toggle(show);
746
1039
  });
747
1040
  this._setShowHideButtonsVisibility();
748
1041
  }
@@ -836,20 +1129,12 @@ var ElementHighlighter = class {
836
1129
  delete this._cancelAutoHideTimer;
837
1130
  };
838
1131
  }
1132
+ this._unobserve();
839
1133
  this._intersectionObserver = new IntersectionObserver(([entry]) => {
840
- if (entry) {
841
- const rect = entry.boundingClientRect;
842
- const body = win.document.body;
843
- const style = container.style;
844
- if (container.parentElement !== body) {
845
- body.appendChild(container);
846
- }
847
- style.width = `${rect.width}px`;
848
- style.height = `${rect.height}px`;
849
- style.top = `${rect.top}px`;
850
- style.left = `${rect.left}px`;
851
- container.style.display = "block";
1134
+ if (!entry) {
1135
+ return;
852
1136
  }
1137
+ this._renderHighlightRect(entry.boundingClientRect, win.document.body);
853
1138
  });
854
1139
  this._intersectionObserver.observe(element);
855
1140
  }
@@ -864,6 +1149,21 @@ var ElementHighlighter = class {
864
1149
  delete this._container;
865
1150
  delete this._window;
866
1151
  }
1152
+ _renderHighlightRect(rect, body) {
1153
+ const container = this._container;
1154
+ if (!container) {
1155
+ return;
1156
+ }
1157
+ if (container.parentElement !== body) {
1158
+ body.appendChild(container);
1159
+ }
1160
+ const style = container.style;
1161
+ style.width = `${rect.width}px`;
1162
+ style.height = `${rect.height}px`;
1163
+ style.top = `${rect.top}px`;
1164
+ style.left = `${rect.left}px`;
1165
+ style.display = "block";
1166
+ }
867
1167
  _hide() {
868
1168
  this._container && (this._container.style.display = "none");
869
1169
  }
@@ -1589,6 +1889,7 @@ var AtomicRule = class extends ValidationRule {
1589
1889
  __publicField(this, "type", 1 /* Error */);
1590
1890
  __publicField(this, "name", "atomic");
1591
1891
  __publicField(this, "anchored", true);
1892
+ __publicField(this, "groupName", "Atomic violation");
1592
1893
  }
1593
1894
  accept(element) {
1594
1895
  return matchesSelector(element, focusableElementSelector);
@@ -1653,6 +1954,7 @@ var FocusableElementLabelRule = class extends ValidationRule {
1653
1954
  __publicField(this, "type", 1 /* Error */);
1654
1955
  __publicField(this, "name", "FocusableElementLabelRule");
1655
1956
  __publicField(this, "anchored", true);
1957
+ __publicField(this, "groupName", "Missing text label");
1656
1958
  }
1657
1959
  _isAriaHidden(element) {
1658
1960
  return element.ownerDocument.evaluate(
@@ -1828,6 +2130,7 @@ var ContrastRule = class extends ValidationRule {
1828
2130
  __publicField(this, "type", 1 /* Error */);
1829
2131
  __publicField(this, "name", "ContrastRule");
1830
2132
  __publicField(this, "anchored", true);
2133
+ __publicField(this, "groupName", "Insufficient color contrast");
1831
2134
  }
1832
2135
  accept(element) {
1833
2136
  if (!isElementVisible(element)) {
@@ -1917,6 +2220,7 @@ var ExistingIdRule = class extends ValidationRule {
1917
2220
  __publicField(this, "type", 1 /* Error */);
1918
2221
  __publicField(this, "name", "existing-id");
1919
2222
  __publicField(this, "anchored", true);
2223
+ __publicField(this, "groupName", "Referenced element not found");
1920
2224
  }
1921
2225
  accept(element) {
1922
2226
  return element.hasAttribute("aria-labelledby") || element.hasAttribute("aria-describedby") || element.tagName === "LABEL" && !!element.htmlFor;
@@ -1956,6 +2260,7 @@ var FocusLostRule = class extends ValidationRule {
1956
2260
  __publicField(this, "type", 1 /* Error */);
1957
2261
  __publicField(this, "name", "focus-lost");
1958
2262
  __publicField(this, "anchored", false);
2263
+ __publicField(this, "groupName", "Focus lost");
1959
2264
  __publicField(this, "_focusLostTimeout", 2e3);
1960
2265
  // For now reporting lost focus after 2 seconds of it being lost.
1961
2266
  __publicField(this, "_clearScheduledFocusLost");
@@ -2065,6 +2370,7 @@ var BadFocusRule = class extends ValidationRule {
2065
2370
  __publicField(this, "type", 1 /* Error */);
2066
2371
  __publicField(this, "name", "bad-focus");
2067
2372
  __publicField(this, "anchored", false);
2373
+ __publicField(this, "groupName", "Bad focus");
2068
2374
  __publicField(this, "_lastFocusStack");
2069
2375
  __publicField(this, "_lastBlurStack");
2070
2376
  __publicField(this, "_clearCheckTimer");
@@ -2116,6 +2422,7 @@ var FindElementRule = class extends ValidationRule {
2116
2422
  __publicField(this, "type", 2 /* Warning */);
2117
2423
  __publicField(this, "name", "find-element");
2118
2424
  __publicField(this, "anchored", true);
2425
+ __publicField(this, "groupName", "Element found");
2119
2426
  __publicField(this, "_conditions", {});
2120
2427
  }
2121
2428
  addCondition(name, condition) {
@@ -2164,6 +2471,7 @@ var RequiredParentRule = class extends ValidationRule {
2164
2471
  __publicField(this, "type", 1 /* Error */);
2165
2472
  __publicField(this, "name", "aria-required-parent");
2166
2473
  __publicField(this, "anchored", true);
2474
+ __publicField(this, "groupName", "Missing required parent");
2167
2475
  __publicField(this, "parentRequirements", /* @__PURE__ */ new Map([
2168
2476
  [
2169
2477
  "LI",
@@ -2480,6 +2788,7 @@ var NestedInteractiveElementRule = class extends ValidationRule {
2480
2788
  __publicField(this, "type", 1 /* Error */);
2481
2789
  __publicField(this, "name", "NestedInteractiveElementRule");
2482
2790
  __publicField(this, "anchored", true);
2791
+ __publicField(this, "groupName", "Nested interactive element");
2483
2792
  }
2484
2793
  _isAriaHidden(element) {
2485
2794
  return element.ownerDocument.evaluate(
@@ -2577,6 +2886,7 @@ var TabIndexRule = class extends ValidationRule {
2577
2886
  __publicField(this, "type", 2 /* Warning */);
2578
2887
  __publicField(this, "name", "tabindex");
2579
2888
  __publicField(this, "anchored", true);
2889
+ __publicField(this, "groupName", "Positive tabindex");
2580
2890
  }
2581
2891
  accept(element) {
2582
2892
  return element.hasAttribute("tabindex");