abledom 0.3.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/esm/index.js CHANGED
@@ -13,11 +13,11 @@ var ValidationRule = class {
13
13
  constructor() {
14
14
  __publicField(this, "_window");
15
15
  __publicField(this, "_exceptions", []);
16
- __publicField(this, "_onNotification");
16
+ __publicField(this, "_onIssue");
17
17
  }
18
- static init(instance, window, onNotification) {
18
+ static init(instance, window, onIssue) {
19
19
  instance._window = window;
20
- instance._onNotification = onNotification;
20
+ instance._onIssue = onIssue;
21
21
  }
22
22
  static dispose(instance) {
23
23
  instance.dispose();
@@ -32,7 +32,7 @@ var ValidationRule = class {
32
32
  }
33
33
  dispose() {
34
34
  this._window = void 0;
35
- this._onNotification = void 0;
35
+ this._onIssue = void 0;
36
36
  this._exceptions = [];
37
37
  }
38
38
  addException(checkException) {
@@ -51,14 +51,14 @@ var ValidationRule = class {
51
51
  get window() {
52
52
  return this._window;
53
53
  }
54
- notify(notification) {
54
+ notify(issue) {
55
55
  var _a;
56
- (_a = this._onNotification) == null ? void 0 : _a.call(this, this, notification);
56
+ (_a = this._onIssue) == null ? void 0 : _a.call(this, this, issue);
57
57
  }
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 .notifications-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-notifications-container {\n overflow: scroll;\n max-height: calc(100vh - 100px);\n}\n\n#abledom-report.abledom-align-right .abledom-notifications-container {\n text-align: right;\n}\n\n.abledom-notification-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-notification {\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-notification_warning {\n background-color: rgba(163, 82, 1, 0.7);\n}\n.abledom-notification_info {\n background-color: rgba(0, 0, 255, 0.7);\n}\n\n.abledom-notification .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-notification .button:hover {\n opacity: 0.7;\n}\n\n.abledom-notification .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\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";
62
62
 
63
63
  // src/ui/domBuilder.ts
64
64
  var DOMBuilder = class {
@@ -116,7 +116,7 @@ var DOMBuilder = class {
116
116
  };
117
117
 
118
118
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/close.svg
119
- var close_default = function buildSVG(parent) {
119
+ var close_default = (function buildSVG(parent) {
120
120
  const builder = new DOMBuilder(parent);
121
121
  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");
122
122
  builder.openTag("circle", { "cx": "12", "cy": "12", "r": "10" }, void 0, "http://www.w3.org/2000/svg");
@@ -127,10 +127,10 @@ var close_default = function buildSVG(parent) {
127
127
  builder.closeTag();
128
128
  builder.closeTag();
129
129
  return parent.firstElementChild;
130
- };
130
+ });
131
131
 
132
132
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/help.svg
133
- var help_default = function buildSVG2(parent) {
133
+ var help_default = (function buildSVG2(parent) {
134
134
  const builder = new DOMBuilder(parent);
135
135
  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");
136
136
  builder.openTag("circle", { "cx": "12", "cy": "12", "r": "10" }, void 0, "http://www.w3.org/2000/svg");
@@ -141,10 +141,10 @@ var help_default = function buildSVG2(parent) {
141
141
  builder.closeTag();
142
142
  builder.closeTag();
143
143
  return parent.firstElementChild;
144
- };
144
+ });
145
145
 
146
146
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/log.svg
147
- var log_default = function buildSVG3(parent) {
147
+ var log_default = (function buildSVG3(parent) {
148
148
  const builder = new DOMBuilder(parent);
149
149
  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");
150
150
  builder.openTag("polyline", { "points": "4 7 9 12 4 17" }, void 0, "http://www.w3.org/2000/svg");
@@ -153,10 +153,10 @@ var log_default = function buildSVG3(parent) {
153
153
  builder.closeTag();
154
154
  builder.closeTag();
155
155
  return parent.firstElementChild;
156
- };
156
+ });
157
157
 
158
158
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/reveal.svg
159
- var reveal_default = function buildSVG4(parent) {
159
+ var reveal_default = (function buildSVG4(parent) {
160
160
  const builder = new DOMBuilder(parent);
161
161
  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");
162
162
  builder.openTag("circle", { "cx": "12", "cy": "12", "r": "10" }, void 0, "http://www.w3.org/2000/svg");
@@ -171,10 +171,10 @@ var reveal_default = function buildSVG4(parent) {
171
171
  builder.closeTag();
172
172
  builder.closeTag();
173
173
  return parent.firstElementChild;
174
- };
174
+ });
175
175
 
176
176
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/bug.svg
177
- var bug_default = function buildSVG5(parent) {
177
+ var bug_default = (function buildSVG5(parent) {
178
178
  const builder = new DOMBuilder(parent);
179
179
  builder.openTag("svg", { "width": "20", "height": "20", "viewBox": "0 0 20 20", "fill": "none", "stroke": "currentColor" }, void 0, "http://www.w3.org/2000/svg");
180
180
  builder.openTag("ellipse", { "cx": "10", "cy": "12", "rx": "4", "ry": "5", "stroke-width": "1.5" }, void 0, "http://www.w3.org/2000/svg");
@@ -199,10 +199,10 @@ var bug_default = function buildSVG5(parent) {
199
199
  builder.closeTag();
200
200
  builder.closeTag();
201
201
  return parent.firstElementChild;
202
- };
202
+ });
203
203
 
204
204
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/hideall.svg
205
- var hideall_default = function buildSVG6(parent) {
205
+ var hideall_default = (function buildSVG6(parent) {
206
206
  const builder = new DOMBuilder(parent);
207
207
  builder.openTag("svg", { "width": "20", "height": "20", "viewBox": "0 0 20 20", "fill": "none", "stroke": "currentColor" }, void 0, "http://www.w3.org/2000/svg");
208
208
  builder.openTag("path", { "d": "M11.44 17.5a1.67 1.67 0 0 1-2.89 0", "stroke-width": "1.5" }, void 0, "http://www.w3.org/2000/svg");
@@ -213,10 +213,10 @@ var hideall_default = function buildSVG6(parent) {
213
213
  builder.closeTag();
214
214
  builder.closeTag();
215
215
  return parent.firstElementChild;
216
- };
216
+ });
217
217
 
218
218
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/muteall.svg
219
- var muteall_default = function buildSVG7(parent) {
219
+ var muteall_default = (function buildSVG7(parent) {
220
220
  const builder = new DOMBuilder(parent);
221
221
  builder.openTag("svg", { "width": "20", "height": "20", "viewBox": "0 0 20 20", "fill": "none", "stroke": "currentColor" }, void 0, "http://www.w3.org/2000/svg");
222
222
  builder.openTag("path", { "d": "M11.44 17.5a1.67 1.67 0 0 1-2.89 0", "stroke-width": "1.5" }, void 0, "http://www.w3.org/2000/svg");
@@ -229,10 +229,10 @@ var muteall_default = function buildSVG7(parent) {
229
229
  builder.closeTag();
230
230
  builder.closeTag();
231
231
  return parent.firstElementChild;
232
- };
232
+ });
233
233
 
234
234
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/showall.svg
235
- var showall_default = function buildSVG8(parent) {
235
+ var showall_default = (function buildSVG8(parent) {
236
236
  const builder = new DOMBuilder(parent);
237
237
  builder.openTag("svg", { "width": "20", "height": "20", "viewBox": "0 0 20 20", "fill": "none", "stroke": "currentColor" }, void 0, "http://www.w3.org/2000/svg");
238
238
  builder.openTag("path", { "d": "M11.44 17.5a1.67 1.67 0 0 1-2.89 0", "stroke-width": "1.5" }, void 0, "http://www.w3.org/2000/svg");
@@ -241,65 +241,67 @@ var showall_default = function buildSVG8(parent) {
241
241
  builder.closeTag();
242
242
  builder.closeTag();
243
243
  return parent.firstElementChild;
244
- };
244
+ });
245
245
 
246
246
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/aligntopleft.svg
247
- var aligntopleft_default = function buildSVG9(parent) {
247
+ var aligntopleft_default = (function buildSVG9(parent) {
248
248
  const builder = new DOMBuilder(parent);
249
249
  builder.openTag("svg", { "width": "20", "height": "20", "viewBox": "0 0 20 20", "fill": "none", "stroke": "currentColor" }, void 0, "http://www.w3.org/2000/svg");
250
250
  builder.openTag("rect", { "x": "3", "y": "3", "width": "6", "height": "6", "stroke-width": "2" }, void 0, "http://www.w3.org/2000/svg");
251
251
  builder.closeTag();
252
252
  builder.closeTag();
253
253
  return parent.firstElementChild;
254
- };
254
+ });
255
255
 
256
256
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/aligntopright.svg
257
- var aligntopright_default = function buildSVG10(parent) {
257
+ var aligntopright_default = (function buildSVG10(parent) {
258
258
  const builder = new DOMBuilder(parent);
259
259
  builder.openTag("svg", { "width": "20", "height": "20", "viewBox": "0 0 20 20", "fill": "none", "stroke": "currentColor" }, void 0, "http://www.w3.org/2000/svg");
260
260
  builder.openTag("rect", { "x": "11", "y": "3", "width": "6", "height": "6", "stroke-width": "2" }, void 0, "http://www.w3.org/2000/svg");
261
261
  builder.closeTag();
262
262
  builder.closeTag();
263
263
  return parent.firstElementChild;
264
- };
264
+ });
265
265
 
266
266
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/alignbottomright.svg
267
- var alignbottomright_default = function buildSVG11(parent) {
267
+ var alignbottomright_default = (function buildSVG11(parent) {
268
268
  const builder = new DOMBuilder(parent);
269
269
  builder.openTag("svg", { "width": "20", "height": "20", "viewBox": "0 0 20 20", "fill": "none", "stroke": "currentColor" }, void 0, "http://www.w3.org/2000/svg");
270
270
  builder.openTag("rect", { "x": "11", "y": "11", "width": "6", "height": "6", "stroke-width": "2" }, void 0, "http://www.w3.org/2000/svg");
271
271
  builder.closeTag();
272
272
  builder.closeTag();
273
273
  return parent.firstElementChild;
274
- };
274
+ });
275
275
 
276
276
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/alignbottomleft.svg
277
- var alignbottomleft_default = function buildSVG12(parent) {
277
+ var alignbottomleft_default = (function buildSVG12(parent) {
278
278
  const builder = new DOMBuilder(parent);
279
279
  builder.openTag("svg", { "width": "20", "height": "20", "viewBox": "0 0 20 20", "fill": "none", "stroke": "currentColor" }, void 0, "http://www.w3.org/2000/svg");
280
280
  builder.openTag("rect", { "x": "3", "y": "11", "width": "6", "height": "6", "stroke-width": "2" }, void 0, "http://www.w3.org/2000/svg");
281
281
  builder.closeTag();
282
282
  builder.closeTag();
283
283
  return parent.firstElementChild;
284
- };
284
+ });
285
285
 
286
286
  // src/ui/ui.ts
287
287
  var pressedClass = "pressed";
288
- var NotificationUI = class {
289
- constructor(win, core, rule, notificationsUI) {
288
+ var IssueUI = class {
289
+ constructor(win, core, rule, issuesUI) {
290
290
  __publicField(this, "_core");
291
- __publicField(this, "_notificationsUI");
291
+ __publicField(this, "_issuesUI");
292
292
  __publicField(this, "_wrapper");
293
293
  __publicField(this, "_rule");
294
294
  __publicField(this, "_onToggle");
295
295
  __publicField(this, "isHidden", false);
296
296
  this._core = core;
297
297
  this._rule = rule;
298
- this._notificationsUI = notificationsUI;
299
- this._wrapper = win.document.createElement(
300
- "div"
301
- );
302
- notificationsUI.addNotification(this);
298
+ this._issuesUI = issuesUI;
299
+ if (!issuesUI.headless) {
300
+ this._wrapper = win.document.createElement(
301
+ "div"
302
+ );
303
+ }
304
+ issuesUI.addIssue(this);
303
305
  }
304
306
  static setOnToggle(instance, onToggle) {
305
307
  instance._onToggle = onToggle;
@@ -307,27 +309,26 @@ var NotificationUI = class {
307
309
  static getElement(instance) {
308
310
  return instance._wrapper;
309
311
  }
310
- update(notification) {
312
+ update(issue) {
311
313
  const rule = this._rule;
312
314
  const wrapper = this._wrapper;
313
- const element = notification.element;
315
+ const element = issue.element;
316
+ if (!wrapper) {
317
+ return;
318
+ }
314
319
  wrapper.__abledomui = true;
315
320
  wrapper.textContent = "";
316
- new DOMBuilder(wrapper).openTag(
317
- "div",
318
- { class: "abledom-notification-container" },
319
- (container) => {
320
- container.onmouseenter = () => {
321
- var _a;
322
- element && ((_a = this._notificationsUI) == null ? void 0 : _a.highlight(element));
323
- };
324
- container.onmouseleave = () => {
325
- var _a;
326
- (_a = this._notificationsUI) == null ? void 0 : _a.highlight(null);
327
- };
328
- }
329
- ).openTag("div", {
330
- class: `abledom-notification${rule.type === 2 /* Warning */ ? " abledom-notification_warning" : rule.type === 3 /* Info */ ? " abledom-notification_info" : ""}`
321
+ new DOMBuilder(wrapper).openTag("div", { class: "abledom-issue-container" }, (container) => {
322
+ container.onmouseenter = () => {
323
+ var _a;
324
+ element && ((_a = this._issuesUI) == null ? void 0 : _a.highlight(element));
325
+ };
326
+ container.onmouseleave = () => {
327
+ var _a;
328
+ (_a = this._issuesUI) == null ? void 0 : _a.highlight(null);
329
+ };
330
+ }).openTag("div", {
331
+ class: `abledom-issue${rule.type === 2 /* Warning */ ? " abledom-issue_warning" : rule.type === 3 /* Info */ ? " abledom-issue_info" : ""}`
331
332
  }).openTag(
332
333
  "button",
333
334
  {
@@ -336,7 +337,7 @@ var NotificationUI = class {
336
337
  },
337
338
  (logButton) => {
338
339
  logButton.onclick = () => {
339
- const { id, message, element: element2, rel, help, ...extra } = notification;
340
+ const { id, message, element: element2, rel, help, ...extra } = issue;
340
341
  this._core.log(
341
342
  "AbleDOM: ",
342
343
  "\nid:",
@@ -359,12 +360,12 @@ var NotificationUI = class {
359
360
  title: "Scroll element into view"
360
361
  },
361
362
  (revealButton) => {
362
- const element2 = notification.element;
363
+ const element2 = issue.element;
363
364
  if (element2) {
364
365
  revealButton.onclick = () => {
365
366
  var _a;
366
367
  element2.scrollIntoView({ block: "center" });
367
- (_a = this._notificationsUI) == null ? void 0 : _a.highlight(element2);
368
+ (_a = this._issuesUI) == null ? void 0 : _a.highlight(element2);
368
369
  };
369
370
  } else {
370
371
  revealButton.style.display = "none";
@@ -378,29 +379,29 @@ var NotificationUI = class {
378
379
  },
379
380
  (bugReportButton) => {
380
381
  var _a, _b;
381
- const bugReport = (_a = this._notificationsUI) == null ? void 0 : _a.bugReport;
382
- if (bugReport == null ? void 0 : bugReport.isVisible(notification)) {
383
- const title = (_b = bugReport.getTitle) == null ? void 0 : _b.call(bugReport, notification);
382
+ const bugReport = (_a = this._issuesUI) == null ? void 0 : _a.bugReport;
383
+ if (bugReport == null ? void 0 : bugReport.isVisible(issue)) {
384
+ const title = (_b = bugReport.getTitle) == null ? void 0 : _b.call(bugReport, issue);
384
385
  if (title) {
385
386
  bugReportButton.title = title;
386
387
  }
387
388
  bugReportButton.onclick = () => {
388
- bugReport.onClick(notification);
389
+ bugReport.onClick(issue);
389
390
  };
390
391
  } else {
391
392
  bugReportButton.style.display = "none";
392
393
  }
393
394
  }
394
- ).element(bug_default).closeTag().text(notification.message).openTag(
395
+ ).element(bug_default).closeTag().text(issue.message).openTag(
395
396
  "a",
396
397
  {
397
398
  class: "button close",
398
- href: notification.help || "/",
399
+ href: issue.help || "/",
399
400
  title: "Open help",
400
401
  target: "_blank"
401
402
  },
402
403
  (help) => {
403
- if (!notification.help) {
404
+ if (!issue.help) {
404
405
  help.style.display = "none";
405
406
  }
406
407
  }
@@ -414,13 +415,16 @@ var NotificationUI = class {
414
415
  closeButton.onclick = () => {
415
416
  var _a;
416
417
  this.toggle(false);
417
- (_a = this._notificationsUI) == null ? void 0 : _a.highlight(null);
418
+ (_a = this._issuesUI) == null ? void 0 : _a.highlight(null);
418
419
  };
419
420
  }
420
421
  ).element(close_default).closeTag().closeTag().closeTag();
421
422
  }
422
423
  toggle(show, initial = false) {
423
424
  var _a;
425
+ if (!this._wrapper) {
426
+ return;
427
+ }
424
428
  this.isHidden = !show;
425
429
  if (!initial) {
426
430
  (_a = this._onToggle) == null ? void 0 : _a.call(this, this, show);
@@ -431,18 +435,18 @@ var NotificationUI = class {
431
435
  this._wrapper.style.display = show ? "block" : "none";
432
436
  }
433
437
  dispose() {
434
- var _a;
435
- this._wrapper.remove();
436
- (_a = this._notificationsUI) == null ? void 0 : _a.removeNotification(this);
437
- delete this._notificationsUI;
438
+ var _a, _b;
439
+ (_a = this._wrapper) == null ? void 0 : _a.remove();
440
+ (_b = this._issuesUI) == null ? void 0 : _b.removeIssue(this);
441
+ delete this._issuesUI;
438
442
  }
439
443
  };
440
- var NotificationsUI = class {
444
+ var IssuesUI = class {
441
445
  constructor(win, props) {
442
446
  __publicField(this, "_container");
443
- __publicField(this, "_notificationsContainer");
447
+ __publicField(this, "_issuesContainer");
444
448
  __publicField(this, "_menuElement");
445
- __publicField(this, "_notificationCountElement");
449
+ __publicField(this, "_issueCountElement");
446
450
  __publicField(this, "_showAllButton");
447
451
  __publicField(this, "_hideAllButton");
448
452
  __publicField(this, "_alignBottomLeftButton");
@@ -450,10 +454,15 @@ var NotificationsUI = class {
450
454
  __publicField(this, "_alignTopRightButton");
451
455
  __publicField(this, "_alignBottomRightButton");
452
456
  __publicField(this, "_isMuted", false);
453
- __publicField(this, "_notifications", /* @__PURE__ */ new Set());
457
+ __publicField(this, "_issues", /* @__PURE__ */ new Set());
454
458
  __publicField(this, "_highlighter");
455
459
  __publicField(this, "bugReport");
460
+ __publicField(this, "headless");
456
461
  this.bugReport = props.bugReport;
462
+ this.headless = !!props.headless;
463
+ if (this.headless) {
464
+ return;
465
+ }
457
466
  const doc = win.document;
458
467
  const container = this._container = doc.createElement("div");
459
468
  container.__abledomui = true;
@@ -462,10 +471,10 @@ var NotificationsUI = class {
462
471
  style.type = "text/css";
463
472
  style.appendChild(doc.createTextNode(ui_default));
464
473
  container.appendChild(style);
465
- const notificationsContainer = this._notificationsContainer = doc.createElement("div");
466
- notificationsContainer.__abledomui = true;
467
- notificationsContainer.className = "abledom-notifications-container";
468
- container.appendChild(notificationsContainer);
474
+ const issuesContainer = this._issuesContainer = doc.createElement("div");
475
+ issuesContainer.__abledomui = true;
476
+ issuesContainer.className = "abledom-issues-container";
477
+ container.appendChild(issuesContainer);
469
478
  const menuElement = this._menuElement = doc.createElement("div");
470
479
  menuElement.__abledomui = true;
471
480
  menuElement.className = "abledom-menu-container";
@@ -473,17 +482,17 @@ var NotificationsUI = class {
473
482
  new DOMBuilder(menuElement).openTag("div", { class: "abledom-menu" }).openTag(
474
483
  "span",
475
484
  {
476
- class: "notifications-count",
477
- title: "Number of notifications"
485
+ class: "issues-count",
486
+ title: "Number of issues"
478
487
  },
479
- (notificationCountElement) => {
480
- this._notificationCountElement = notificationCountElement;
488
+ (issueCountElement) => {
489
+ this._issueCountElement = issueCountElement;
481
490
  }
482
491
  ).closeTag().openTag(
483
492
  "button",
484
493
  {
485
494
  class: "button",
486
- title: "Show all notifications"
495
+ title: "Show all issues"
487
496
  },
488
497
  (showAllButton) => {
489
498
  this._showAllButton = showAllButton;
@@ -495,7 +504,7 @@ var NotificationsUI = class {
495
504
  "button",
496
505
  {
497
506
  class: "button",
498
- title: "Hide all notifications"
507
+ title: "Hide all issues"
499
508
  },
500
509
  (hideAllButton) => {
501
510
  this._hideAllButton = hideAllButton;
@@ -507,21 +516,15 @@ var NotificationsUI = class {
507
516
  "button",
508
517
  {
509
518
  class: "button",
510
- title: "Mute newly appearing notifications"
519
+ title: "Mute newly appearing issues"
511
520
  },
512
521
  (muteButton) => {
513
522
  muteButton.onclick = () => {
514
523
  const isMuted = this._isMuted = muteButton.classList.toggle(pressedClass);
515
524
  if (isMuted) {
516
- muteButton.setAttribute(
517
- "title",
518
- "Unmute newly appearing notifications"
519
- );
525
+ muteButton.setAttribute("title", "Unmute newly appearing issues");
520
526
  } else {
521
- muteButton.setAttribute(
522
- "title",
523
- "Mute newly appearing notifications"
524
- );
527
+ muteButton.setAttribute("title", "Mute newly appearing issues");
525
528
  }
526
529
  };
527
530
  }
@@ -529,7 +532,7 @@ var NotificationsUI = class {
529
532
  "button",
530
533
  {
531
534
  class: "button align-button align-button-first pressed",
532
- title: "Attach notifications to bottom left"
535
+ title: "Attach issues to bottom left"
533
536
  },
534
537
  (alignBottomLeftButton) => {
535
538
  this._alignBottomLeftButton = alignBottomLeftButton;
@@ -541,7 +544,7 @@ var NotificationsUI = class {
541
544
  "button",
542
545
  {
543
546
  class: "button align-button",
544
- title: "Attach notifications to top left"
547
+ title: "Attach issues to top left"
545
548
  },
546
549
  (alignTopLeftButton) => {
547
550
  this._alignTopLeftButton = alignTopLeftButton;
@@ -553,7 +556,7 @@ var NotificationsUI = class {
553
556
  "button",
554
557
  {
555
558
  class: "button align-button",
556
- title: "Attach notifications to top right"
559
+ title: "Attach issues to top right"
557
560
  },
558
561
  (alignTopRightButton) => {
559
562
  this._alignTopRightButton = alignTopRightButton;
@@ -565,7 +568,7 @@ var NotificationsUI = class {
565
568
  "button",
566
569
  {
567
570
  class: "button align-button align-button-last",
568
- title: "Attach notifications to bottom right"
571
+ title: "Attach issues to bottom right"
569
572
  },
570
573
  (alignBottomRightButton) => {
571
574
  this._alignBottomRightButton = alignBottomRightButton;
@@ -579,7 +582,7 @@ var NotificationsUI = class {
579
582
  }
580
583
  setUIAlignment(alignment) {
581
584
  var _a, _b, _c, _d, _e, _f, _g, _h;
582
- if (!this._container || !this._notificationsContainer || !this._menuElement) {
585
+ if (!this._container || !this._issuesContainer || !this._menuElement) {
583
586
  return;
584
587
  }
585
588
  (_a = this._alignBottomLeftButton) == null ? void 0 : _a.classList.remove(pressedClass);
@@ -593,16 +596,16 @@ var NotificationsUI = class {
593
596
  "abledom-align-bottom"
594
597
  );
595
598
  let containerClasses = [];
596
- let notificationsFirst = false;
599
+ let issuesFirst = false;
597
600
  switch (alignment) {
598
601
  case "bottom-left" /* BottomLeft */:
599
602
  containerClasses = ["abledom-align-left", "abledom-align-bottom"];
600
- notificationsFirst = true;
603
+ issuesFirst = true;
601
604
  (_e = this._alignBottomLeftButton) == null ? void 0 : _e.classList.add(pressedClass);
602
605
  break;
603
606
  case "bottom-right" /* BottomRight */:
604
607
  containerClasses = ["abledom-align-right", "abledom-align-bottom"];
605
- notificationsFirst = true;
608
+ issuesFirst = true;
606
609
  (_f = this._alignBottomRightButton) == null ? void 0 : _f.classList.add(pressedClass);
607
610
  break;
608
611
  case "top-left" /* TopLeft */:
@@ -616,18 +619,18 @@ var NotificationsUI = class {
616
619
  }
617
620
  this._container.classList.add(...containerClasses);
618
621
  this._container.insertBefore(
619
- this._notificationsContainer,
620
- notificationsFirst ? this._menuElement : null
622
+ this._issuesContainer,
623
+ issuesFirst ? this._menuElement : null
621
624
  );
622
625
  }
623
- _setNotificationsCount(count) {
626
+ _setIssuesCount(count) {
624
627
  if (!this._menuElement) {
625
628
  return;
626
629
  }
627
- const countElement = this._notificationCountElement;
630
+ const countElement = this._issueCountElement;
628
631
  if (countElement && count > 0) {
629
632
  countElement.textContent = "";
630
- new DOMBuilder(countElement).openTag("strong").text(`${count}`).closeTag().text(` notification${count > 1 ? "s" : ""}`);
633
+ new DOMBuilder(countElement).openTag("strong").text(`${count}`).closeTag().text(` issue${count > 1 ? "s" : ""}`);
631
634
  this._menuElement.style.display = "block";
632
635
  } else {
633
636
  this._menuElement.style.display = "none";
@@ -641,8 +644,8 @@ var NotificationsUI = class {
641
644
  }
642
645
  let allHidden = true;
643
646
  let allVisible = true;
644
- for (let notification of this._notifications) {
645
- if (notification.isHidden) {
647
+ for (let issue of this._issues) {
648
+ if (issue.isHidden) {
646
649
  allVisible = false;
647
650
  } else {
648
651
  allHidden = false;
@@ -654,44 +657,46 @@ var NotificationsUI = class {
654
657
  hideAllButton.style.display = allHidden ? "none" : "block";
655
658
  showAllButton.style.display = allVisible ? "none" : "block";
656
659
  }
657
- addNotification(notification) {
658
- if (!this._notificationsContainer) {
659
- throw new Error("NotificationsUI is not initialized");
660
+ addIssue(issue) {
661
+ if (this._issues.has(issue)) {
662
+ return;
660
663
  }
661
- if (this._notifications.has(notification)) {
664
+ this._issues.add(issue);
665
+ if (this.headless) {
662
666
  return;
663
667
  }
668
+ if (!this._issuesContainer) {
669
+ throw new Error("IssuesUI is not initialized");
670
+ }
664
671
  if (this._isMuted) {
665
- notification.toggle(false, true);
672
+ issue.toggle(false, true);
666
673
  }
667
- this._notifications.add(notification);
668
- this._notificationsContainer.appendChild(
669
- NotificationUI.getElement(notification)
670
- );
671
- NotificationUI.setOnToggle(notification, () => {
674
+ const issueUIWraper = IssueUI.getElement(issue);
675
+ issueUIWraper && this._issuesContainer.appendChild(issueUIWraper);
676
+ IssueUI.setOnToggle(issue, () => {
672
677
  this._setShowHideButtonsVisibility();
673
678
  });
674
- this._setNotificationsCount(this._notifications.size);
679
+ this._setIssuesCount(this._issues.size);
675
680
  this._setShowHideButtonsVisibility();
676
681
  }
677
- removeNotification(notification) {
678
- if (!this._notifications.has(notification)) {
682
+ removeIssue(issue) {
683
+ if (!this._issues.has(issue)) {
679
684
  return;
680
685
  }
681
- this._notifications.delete(notification);
682
- this._setNotificationsCount(this._notifications.size);
686
+ this._issues.delete(issue);
687
+ this._setIssuesCount(this._issues.size);
683
688
  this._setShowHideButtonsVisibility();
684
689
  this.highlight(null);
685
690
  }
686
691
  hideAll() {
687
- this._notifications.forEach((notification) => {
688
- notification.toggle(false);
692
+ this._issues.forEach((issue) => {
693
+ issue.toggle(false);
689
694
  });
690
695
  this._setShowHideButtonsVisibility();
691
696
  }
692
697
  showAll() {
693
- this._notifications.forEach((notification) => {
694
- notification.toggle(true);
698
+ this._issues.forEach((issue) => {
699
+ issue.toggle(true);
695
700
  });
696
701
  this._setShowHideButtonsVisibility();
697
702
  }
@@ -705,9 +710,9 @@ var NotificationsUI = class {
705
710
  (_b = this._container) == null ? void 0 : _b.remove();
706
711
  delete this._highlighter;
707
712
  delete this._container;
708
- delete this._notificationsContainer;
713
+ delete this._issuesContainer;
709
714
  delete this._menuElement;
710
- delete this._notificationCountElement;
715
+ delete this._issueCountElement;
711
716
  delete this._showAllButton;
712
717
  delete this._hideAllButton;
713
718
  delete this._alignBottomLeftButton;
@@ -992,7 +997,7 @@ var AbleDOM = class {
992
997
  __publicField(this, "_props");
993
998
  __publicField(this, "_observer");
994
999
  __publicField(this, "_clearValidationTimeout");
995
- __publicField(this, "_elementsWithNotifications", /* @__PURE__ */ new Set());
1000
+ __publicField(this, "_elementsWithIssues", /* @__PURE__ */ new Set());
996
1001
  __publicField(this, "_changedElementIds", /* @__PURE__ */ new Set());
997
1002
  __publicField(this, "_elementsDependingOnId", /* @__PURE__ */ new Map());
998
1003
  __publicField(this, "_dependantIdsByElement", /* @__PURE__ */ new Map());
@@ -1000,7 +1005,9 @@ var AbleDOM = class {
1000
1005
  __publicField(this, "_rules", []);
1001
1006
  __publicField(this, "_startFunc");
1002
1007
  __publicField(this, "_isStarted", false);
1003
- __publicField(this, "_notificationsUI");
1008
+ __publicField(this, "_issuesUI");
1009
+ __publicField(this, "_idlePromise");
1010
+ __publicField(this, "_idleResolve");
1004
1011
  __publicField(this, "_onFocusIn", (event) => {
1005
1012
  var _a;
1006
1013
  const target = event.target;
@@ -1008,9 +1015,9 @@ var AbleDOM = class {
1008
1015
  return;
1009
1016
  }
1010
1017
  for (const rule of this._rules) {
1011
- const focusNotification = (_a = rule.focused) == null ? void 0 : _a.call(rule, event);
1012
- if (focusNotification) {
1013
- this._addNotification(rule, focusNotification);
1018
+ const focusIssue = (_a = rule.focused) == null ? void 0 : _a.call(rule, event);
1019
+ if (focusIssue) {
1020
+ this._addIssue(rule, focusIssue);
1014
1021
  }
1015
1022
  }
1016
1023
  });
@@ -1021,14 +1028,14 @@ var AbleDOM = class {
1021
1028
  return;
1022
1029
  }
1023
1030
  for (const rule of this._rules) {
1024
- const blurNotification = (_a = rule.blurred) == null ? void 0 : _a.call(rule, event);
1025
- if (blurNotification) {
1026
- this._addNotification(rule, blurNotification);
1031
+ const blurIssue = (_a = rule.blurred) == null ? void 0 : _a.call(rule, event);
1032
+ if (blurIssue) {
1033
+ this._addIssue(rule, blurIssue);
1027
1034
  }
1028
1035
  }
1029
1036
  });
1030
- __publicField(this, "_notifyAsync", (rule, notification) => {
1031
- this._addNotification(rule, notification);
1037
+ __publicField(this, "_notifyAsync", (rule, issue) => {
1038
+ this._addIssue(rule, issue);
1032
1039
  });
1033
1040
  __publicField(this, "log", (...args) => {
1034
1041
  var _a, _b, _c, _d;
@@ -1065,12 +1072,14 @@ var AbleDOM = class {
1065
1072
  }
1066
1073
  (_a = this._clearValidationTimeout) == null ? void 0 : _a.call(this);
1067
1074
  const _validationTimeout = win.setTimeout(() => {
1075
+ var _a2;
1068
1076
  delete this._clearValidationTimeout;
1069
1077
  this._remove(_elementsToRemove);
1070
1078
  this._validate(_elementsToValidate);
1071
1079
  _elementsToRemove.clear();
1072
1080
  _elementsToValidate.clear();
1073
1081
  this._changedElementIds.clear();
1082
+ (_a2 = this._idleResolve) == null ? void 0 : _a2.call(this);
1074
1083
  }, 200);
1075
1084
  this._clearValidationTimeout = () => {
1076
1085
  win.clearTimeout(_validationTimeout);
@@ -1165,65 +1174,70 @@ var AbleDOM = class {
1165
1174
  this._idByElement.delete(element);
1166
1175
  }
1167
1176
  }
1168
- _addNotification(rule, notification) {
1169
- var _a;
1170
- if (!this._notificationsUI) {
1171
- this._notificationsUI = new NotificationsUI(this._win, {
1172
- bugReport: (_a = this._props) == null ? void 0 : _a.bugReport
1177
+ _addIssue(rule, issue) {
1178
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
1179
+ if (!this._issuesUI) {
1180
+ this._issuesUI = new IssuesUI(this._win, {
1181
+ bugReport: (_a = this._props) == null ? void 0 : _a.bugReport,
1182
+ headless: (_b = this._props) == null ? void 0 : _b.headless
1173
1183
  });
1174
1184
  }
1175
- const element = notification == null ? void 0 : notification.element;
1176
- if (!notification) {
1177
- this._removeNotification(element || this._win.document.body, rule);
1185
+ const element = issue == null ? void 0 : issue.element;
1186
+ if (!issue) {
1187
+ this._removeIssue(element || this._win.document.body, rule);
1178
1188
  return;
1179
1189
  }
1180
- let notificationUI;
1190
+ let issueUI;
1191
+ let justUpdate = true;
1181
1192
  if (rule.anchored && element) {
1182
1193
  let abledomOnElement = element.__abledom;
1183
1194
  if (!abledomOnElement) {
1184
1195
  abledomOnElement = element.__abledom = {};
1185
1196
  }
1186
- let notifications = abledomOnElement.notifications;
1187
- if (!notifications) {
1188
- notifications = abledomOnElement.notifications = /* @__PURE__ */ new Map();
1197
+ let issues = abledomOnElement.issues;
1198
+ if (!issues) {
1199
+ issues = abledomOnElement.issues = /* @__PURE__ */ new Map();
1189
1200
  }
1190
- notificationUI = notifications.get(rule);
1191
- if (!notificationUI) {
1192
- notificationUI = new NotificationUI(
1193
- this._win,
1194
- this,
1195
- rule,
1196
- this._notificationsUI
1197
- );
1198
- notifications.set(rule, notificationUI);
1201
+ issueUI = issues.get(rule);
1202
+ if (!issueUI) {
1203
+ issueUI = new IssueUI(this._win, this, rule, this._issuesUI);
1204
+ issues.set(rule, issueUI);
1205
+ 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);
1199
1207
  }
1200
- this._elementsWithNotifications.add(element);
1208
+ this._elementsWithIssues.add(element);
1201
1209
  } else {
1202
- notificationUI = new NotificationUI(
1203
- this._win,
1204
- this,
1210
+ issueUI = new IssueUI(this._win, this, rule, this._issuesUI);
1211
+ 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);
1213
+ }
1214
+ 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,
1205
1219
  rule,
1206
- this._notificationsUI
1220
+ issue
1207
1221
  );
1208
1222
  }
1209
- notificationUI.update(notification);
1210
1223
  }
1211
- _removeNotification(element, rule) {
1212
- var _a;
1224
+ _removeIssue(element, rule) {
1225
+ var _a, _b, _c, _d;
1213
1226
  if (!rule.anchored) {
1214
1227
  return;
1215
1228
  }
1216
- const notifications = (_a = element.__abledom) == null ? void 0 : _a.notifications;
1217
- if (!notifications) {
1229
+ const issues = (_a = element.__abledom) == null ? void 0 : _a.issues;
1230
+ if (!issues) {
1218
1231
  return;
1219
1232
  }
1220
- const notification = notifications.get(rule);
1221
- if (notification) {
1222
- notification.dispose();
1223
- notifications.delete(rule);
1233
+ const issue = issues.get(rule);
1234
+ if (issue) {
1235
+ issue.dispose();
1236
+ 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);
1224
1238
  }
1225
- if (notifications.size === 0) {
1226
- this._elementsWithNotifications.delete(element);
1239
+ if (issues.size === 0) {
1240
+ this._elementsWithIssues.delete(element);
1227
1241
  delete element.__abledom;
1228
1242
  }
1229
1243
  }
@@ -1238,7 +1252,7 @@ var AbleDOM = class {
1238
1252
  }
1239
1253
  elements.forEach((element) => {
1240
1254
  var _a, _b, _c, _d, _e;
1241
- if (isAccessibilityAffectingElement(element) || ((_a = element.__abledom) == null ? void 0 : _a.notifications)) {
1255
+ if (isAccessibilityAffectingElement(element) || ((_a = element.__abledom) == null ? void 0 : _a.issues)) {
1242
1256
  const dependsOnIds = /* @__PURE__ */ new Set();
1243
1257
  for (const rule of this._rules) {
1244
1258
  if (!rule.validate || ((_b = rule.accept) == null ? void 0 : _b.call(rule, element)) === false) {
@@ -1248,16 +1262,16 @@ var AbleDOM = class {
1248
1262
  continue;
1249
1263
  }
1250
1264
  const validationResult = (_c = rule.validate) == null ? void 0 : _c.call(rule, element);
1251
- if (validationResult == null ? void 0 : validationResult.notification) {
1252
- this._addNotification(rule, validationResult.notification);
1265
+ if (validationResult == null ? void 0 : validationResult.issue) {
1266
+ this._addIssue(rule, validationResult.issue);
1253
1267
  const ids = validationResult.dependsOnIds;
1254
1268
  if (ids) {
1255
1269
  for (const id of ids) {
1256
1270
  dependsOnIds.add(id);
1257
1271
  }
1258
1272
  }
1259
- } else if ((_e = (_d = element.__abledom) == null ? void 0 : _d.notifications) == null ? void 0 : _e.has(rule)) {
1260
- this._removeNotification(element, rule);
1273
+ } else if ((_e = (_d = element.__abledom) == null ? void 0 : _d.issues) == null ? void 0 : _e.has(rule)) {
1274
+ this._removeIssue(element, rule);
1261
1275
  }
1262
1276
  }
1263
1277
  this._processElementDependingOnIds(
@@ -1309,10 +1323,25 @@ var AbleDOM = class {
1309
1323
  _remove(elements) {
1310
1324
  elements.forEach((element) => {
1311
1325
  var _a, _b;
1312
- const rules = [...((_b = (_a = element.__abledom) == null ? void 0 : _a.notifications) == null ? void 0 : _b.keys()) || []];
1313
- rules.forEach((rule) => this._removeNotification(element, rule));
1326
+ const rules = [...((_b = (_a = element.__abledom) == null ? void 0 : _a.issues) == null ? void 0 : _b.keys()) || []];
1327
+ rules.forEach((rule) => this._removeIssue(element, rule));
1314
1328
  });
1315
1329
  }
1330
+ idle() {
1331
+ if (!this._clearValidationTimeout) {
1332
+ return Promise.resolve();
1333
+ }
1334
+ if (!this._idlePromise) {
1335
+ this._idlePromise = new Promise((resolve) => {
1336
+ this._idleResolve = () => {
1337
+ delete this._idlePromise;
1338
+ delete this._idleResolve;
1339
+ resolve();
1340
+ };
1341
+ });
1342
+ }
1343
+ return this._idlePromise;
1344
+ }
1316
1345
  addRule(rule) {
1317
1346
  this._rules.push(rule);
1318
1347
  }
@@ -1338,20 +1367,21 @@ var AbleDOM = class {
1338
1367
  (_b = this._startFunc) == null ? void 0 : _b.call(this);
1339
1368
  }
1340
1369
  dispose() {
1341
- var _a, _b, _c;
1370
+ var _a, _b, _c, _d;
1342
1371
  const doc = this._win.document;
1343
1372
  doc.addEventListener("focusin", this._onFocusIn, true);
1344
1373
  doc.addEventListener("focusout", this._onFocusOut, true);
1345
- this._remove(this._elementsWithNotifications);
1346
- this._elementsWithNotifications.clear();
1374
+ this._remove(this._elementsWithIssues);
1375
+ this._elementsWithIssues.clear();
1347
1376
  this._dependantIdsByElement.clear();
1348
1377
  this._elementsDependingOnId.clear();
1349
1378
  this._idByElement.clear();
1350
- (_a = this._notificationsUI) == null ? void 0 : _a.dispose();
1351
- delete this._notificationsUI;
1379
+ (_a = this._issuesUI) == null ? void 0 : _a.dispose();
1380
+ delete this._issuesUI;
1352
1381
  (_b = this._clearValidationTimeout) == null ? void 0 : _b.call(this);
1382
+ (_c = this._idleResolve) == null ? void 0 : _c.call(this);
1353
1383
  for (const rule of this._rules) {
1354
- (_c = rule.stop) == null ? void 0 : _c.call(rule);
1384
+ (_d = rule.stop) == null ? void 0 : _d.call(rule);
1355
1385
  ValidationRule.dispose(rule);
1356
1386
  }
1357
1387
  this._rules = [];
@@ -1401,7 +1431,7 @@ var AtomicRule = class extends ValidationRule {
1401
1431
  ).snapshotItem(0);
1402
1432
  if (parentAtomic) {
1403
1433
  return {
1404
- notification: {
1434
+ issue: {
1405
1435
  id: "focusable-in-atomic",
1406
1436
  message: "Focusable element inside atomic focusable.",
1407
1437
  element,
@@ -1539,7 +1569,7 @@ var FocusableElementLabelRule = class extends ValidationRule {
1539
1569
  }
1540
1570
  }
1541
1571
  return {
1542
- notification: isElementVisible(element) ? {
1572
+ issue: isElementVisible(element) ? {
1543
1573
  id: "focusable-element-label",
1544
1574
  message: "Focusable element must have a non-empty text label.",
1545
1575
  element,
@@ -1550,6 +1580,147 @@ var FocusableElementLabelRule = class extends ValidationRule {
1550
1580
  }
1551
1581
  };
1552
1582
 
1583
+ // src/rules/contrast.ts
1584
+ function hexToRgb(hex) {
1585
+ hex = hex.replace(/^#/, "");
1586
+ if (hex.length === 3) {
1587
+ hex = hex.split("").map((x) => x + x).join("");
1588
+ }
1589
+ if (hex.length !== 6) {
1590
+ return null;
1591
+ }
1592
+ const num = parseInt(hex, 16);
1593
+ return [num >> 16 & 255, num >> 8 & 255, num & 255];
1594
+ }
1595
+ function parseColor(color) {
1596
+ color = color.trim();
1597
+ if (color.startsWith("#")) {
1598
+ return hexToRgb(color);
1599
+ }
1600
+ const rgbMatch = color.match(
1601
+ /^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*[\d.]+)?\)$/
1602
+ );
1603
+ if (rgbMatch) {
1604
+ return [
1605
+ parseInt(rgbMatch[1], 10),
1606
+ parseInt(rgbMatch[2], 10),
1607
+ parseInt(rgbMatch[3], 10)
1608
+ ];
1609
+ }
1610
+ return null;
1611
+ }
1612
+ function luminance([r, g, b]) {
1613
+ const a = [r, g, b].map((v) => {
1614
+ v /= 255;
1615
+ return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
1616
+ });
1617
+ return 0.2126 * a[0] + 0.7152 * a[1] + 0.0722 * a[2];
1618
+ }
1619
+ function contrastRatio(l1, l2) {
1620
+ return (Math.max(l1, l2) + 0.05) / (Math.min(l1, l2) + 0.05);
1621
+ }
1622
+ function isTransparent(color) {
1623
+ if (!color) {
1624
+ return true;
1625
+ }
1626
+ color = color.trim();
1627
+ if (color === "transparent" || color === "rgba(0, 0, 0, 0)") {
1628
+ return true;
1629
+ }
1630
+ const rgbaMatch = color.match(/^rgba?\(\d+,\s*\d+,\s*\d+,\s*([\d.]+)\)$/);
1631
+ if (rgbaMatch && parseFloat(rgbaMatch[1]) === 0) {
1632
+ return true;
1633
+ }
1634
+ return false;
1635
+ }
1636
+ var ContrastRule = class extends ValidationRule {
1637
+ constructor() {
1638
+ super(...arguments);
1639
+ __publicField(this, "type", 1 /* Error */);
1640
+ __publicField(this, "name", "ContrastRule");
1641
+ __publicField(this, "anchored", true);
1642
+ }
1643
+ accept(element) {
1644
+ if (!isElementVisible(element)) {
1645
+ return false;
1646
+ }
1647
+ const hasDirectTextContent = Array.from(element.childNodes).some((node) => {
1648
+ var _a;
1649
+ if (node.nodeType === Node.TEXT_NODE) {
1650
+ const text = (_a = node.textContent) == null ? void 0 : _a.trim();
1651
+ return text && text.length > 0;
1652
+ }
1653
+ return false;
1654
+ });
1655
+ return hasDirectTextContent;
1656
+ }
1657
+ validate(element) {
1658
+ const win = this.window;
1659
+ if (!win) {
1660
+ return null;
1661
+ }
1662
+ const style = win.getComputedStyle(element);
1663
+ const fg = parseColor(style.color);
1664
+ if (!fg) {
1665
+ return null;
1666
+ }
1667
+ const hasChildWithDifferentColor = Array.from(element.children).some(
1668
+ (child) => {
1669
+ var _a;
1670
+ if (child instanceof HTMLElement && ((_a = child.textContent) == null ? void 0 : _a.trim())) {
1671
+ const childStyle = win.getComputedStyle(child);
1672
+ const childColor = parseColor(childStyle.color);
1673
+ if (childColor && (childColor[0] !== fg[0] || childColor[1] !== fg[1] || childColor[2] !== fg[2])) {
1674
+ return true;
1675
+ }
1676
+ }
1677
+ return false;
1678
+ }
1679
+ );
1680
+ if (hasChildWithDifferentColor) {
1681
+ return null;
1682
+ }
1683
+ let bg = null;
1684
+ let el = element;
1685
+ let depth = 0;
1686
+ const maxDepth = 50;
1687
+ while (el && depth < maxDepth) {
1688
+ const bgColor = win.getComputedStyle(el).backgroundColor;
1689
+ if (!isTransparent(bgColor)) {
1690
+ const parsedBg = parseColor(bgColor);
1691
+ if (parsedBg) {
1692
+ bg = parsedBg;
1693
+ break;
1694
+ }
1695
+ }
1696
+ el = el.parentElement;
1697
+ depth++;
1698
+ }
1699
+ if (!bg) {
1700
+ bg = [255, 255, 255];
1701
+ }
1702
+ const l1 = luminance(fg);
1703
+ const l2 = luminance(bg);
1704
+ const ratio = contrastRatio(l1, l2);
1705
+ const fontSize = parseFloat(style.fontSize);
1706
+ const fontWeight = style.fontWeight;
1707
+ const isBold = fontWeight === "bold" || fontWeight === "bolder" || parseInt(fontWeight, 10) >= 700;
1708
+ const isLarge = fontSize >= 24 || fontSize >= 18.66 && isBold;
1709
+ const minRatio = isLarge ? 3 : 4.5;
1710
+ if (ratio < minRatio) {
1711
+ return {
1712
+ issue: {
1713
+ id: "contrast",
1714
+ message: `Text contrast ratio is ${ratio.toFixed(2)}:1, which is below the minimum of ${minRatio}:1 (text: rgb(${fg.join(", ")}), background: rgb(${bg.join(", ")})) on ${element.tagName}`,
1715
+ element,
1716
+ help: "https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html"
1717
+ }
1718
+ };
1719
+ }
1720
+ return null;
1721
+ }
1722
+ };
1723
+
1553
1724
  // src/rules/existingid.ts
1554
1725
  var ExistingIdRule = class extends ValidationRule {
1555
1726
  constructor() {
@@ -1579,7 +1750,7 @@ var ExistingIdRule = class extends ValidationRule {
1579
1750
  }
1580
1751
  }
1581
1752
  return {
1582
- notification: {
1753
+ issue: {
1583
1754
  id: "missing-id",
1584
1755
  message: `Elements with referenced ids do not extist.`,
1585
1756
  element
@@ -1768,7 +1939,7 @@ var FindElementRule = class extends ValidationRule {
1768
1939
  for (const name of Object.keys(this._conditions)) {
1769
1940
  if (this._conditions[name](element)) {
1770
1941
  return {
1771
- notification: {
1942
+ issue: {
1772
1943
  id: "find-element",
1773
1944
  message: `Element found: ${name}.`,
1774
1945
  element
@@ -1800,6 +1971,7 @@ export {
1800
1971
  AbleDOM,
1801
1972
  AtomicRule,
1802
1973
  BadFocusRule,
1974
+ ContrastRule,
1803
1975
  CustomNotifyRule,
1804
1976
  ExistingIdRule,
1805
1977
  FindElementRule,