abledom 0.0.1 → 0.0.3

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
@@ -2,8 +2,63 @@ var __defProp = Object.defineProperty;
2
2
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
4
 
5
+ // src/rules/base.ts
6
+ var ValidationRuleType = /* @__PURE__ */ ((ValidationRuleType2) => {
7
+ ValidationRuleType2[ValidationRuleType2["Error"] = 1] = "Error";
8
+ ValidationRuleType2[ValidationRuleType2["Warning"] = 2] = "Warning";
9
+ ValidationRuleType2[ValidationRuleType2["Info"] = 3] = "Info";
10
+ return ValidationRuleType2;
11
+ })(ValidationRuleType || {});
12
+ var ValidationRule = class {
13
+ constructor() {
14
+ __publicField(this, "_window");
15
+ __publicField(this, "_exceptions", []);
16
+ __publicField(this, "_onNotification");
17
+ }
18
+ static init(instance, window, onNotification) {
19
+ instance._window = window;
20
+ instance._onNotification = onNotification;
21
+ }
22
+ static dispose(instance) {
23
+ instance.dispose();
24
+ }
25
+ static checkExceptions(instance, element) {
26
+ for (const exception of instance._exceptions) {
27
+ if (exception(element)) {
28
+ return true;
29
+ }
30
+ }
31
+ return false;
32
+ }
33
+ dispose() {
34
+ this._window = void 0;
35
+ this._onNotification = void 0;
36
+ this._exceptions = [];
37
+ }
38
+ addException(checkException) {
39
+ var _a;
40
+ (_a = this._exceptions) == null ? void 0 : _a.push(checkException);
41
+ }
42
+ removeException(checkException) {
43
+ const index = this._exceptions.indexOf(checkException);
44
+ if (index >= 0) {
45
+ this._exceptions.splice(index, 1);
46
+ }
47
+ }
48
+ /**
49
+ * Window is set when the rule is added to the AbleDOM instance.
50
+ */
51
+ get window() {
52
+ return this._window;
53
+ }
54
+ notify(notification) {
55
+ var _a;
56
+ (_a = this._onNotification) == null ? void 0 : _a.call(this, this, notification);
57
+ }
58
+ };
59
+
5
60
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/ui.css
6
- 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: absolute;\n z-index: 100500;\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\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 border: 1px solid red;\n box-sizing: border-box;\n display: none;\n opacity: 0.6;\n position: absolute;\n z-index: 100499;\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: absolute;\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 border: 1px solid red;\n box-sizing: border-box;\n display: none;\n opacity: 0.6;\n position: absolute;\n z-index: 100499;\n}\n";
7
62
 
8
63
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/close.svg
9
64
  var close_default = '<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor"\n stroke-width="2" stroke-linecap="round" stroke-linejoin="round"\n xmlns="http://www.w3.org/2000/svg">\n <circle cx="12" cy="12" r="10"/>\n <line x1="15" y1="9" x2="9" y2="15"/>\n <line x1="9" y1="9" x2="15" y2="15"/>\n</svg>\n';
@@ -17,30 +72,80 @@ var log_default = '<svg width="20" height="20" viewBox="0 0 24 24" fill="none" s
17
72
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/reveal.svg
18
73
  var reveal_default = '<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor"\n stroke-width="2" stroke-linecap="round" stroke-linejoin="round"\n xmlns="http://www.w3.org/2000/svg">\n <circle cx="12" cy="12" r="10"/>\n <line x1="12" y1="2" x2="12" y2="6"/>\n <line x1="12" y1="18" x2="12" y2="22"/>\n <line x1="2" y1="12" x2="6" y2="12"/>\n <line x1="18" y1="12" x2="22" y2="12"/>\n</svg>';
19
74
 
75
+ // inline-file:/Users/marata/Documents/Work/abledom/src/ui/hideall.svg
76
+ var hideall_default = '<svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor">\n <path d="M11.44 17.5a1.67 1.67 0 0 1-2.89 0" stroke-width="1.5"/>\n <path d="M15 6.67a5 5 0 0 0-10 0v4.17a1.67 1.67 0 0 1-.83 1.44L3.33 14.17h13.34l-0.83-1.89a1.67 1.67 0 0 1-.83-1.44V6.67z" stroke-width="1.5"/>\n <line x1="1.67" y1="1.67" x2="18.33" y2="18.33" stroke-width="1.5"/>\n</svg>\n';
77
+
78
+ // inline-file:/Users/marata/Documents/Work/abledom/src/ui/muteall.svg
79
+ var muteall_default = '<svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor">\n <path d="M11.44 17.5a1.67 1.67 0 0 1-2.89 0" stroke-width="1.5"/>\n <path d="M15 6.67a5 5 0 0 0-10 0v4.17a1.67 1.67 0 0 1-.83 1.44L3.33 14.17h13.34l-0.83-1.89a1.67 1.67 0 0 1-.83-1.44V6.67z" stroke-width="1.5"/>\n <line x1="1.67" y1="1.67" x2="18.33" y2="18.33" stroke-width="1.5"/>\n <line x1="18.33" y1="1.67" x2="1.67" y2="18.33" stroke-width="1.5"/>\n</svg>\n';
80
+
81
+ // inline-file:/Users/marata/Documents/Work/abledom/src/ui/showall.svg
82
+ var showall_default = '<svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor">\n <path d="M11.44 17.5a1.67 1.67 0 0 1-2.89 0" stroke-width="1.5"/>\n <path d="M15 6.67a5 5 0 0 0-10 0v4.17a1.67 1.67 0 0 1-.83 1.44L3.33 14.17h13.34l-0.83-1.89a1.67 1.67 0 0 1-.83-1.44V6.67z" stroke-width="1.5"/>\n</svg>\n';
83
+
84
+ // inline-file:/Users/marata/Documents/Work/abledom/src/ui/aligntopleft.svg
85
+ var aligntopleft_default = '<svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor">\n <rect x="3" y="3" width="6" height="6" stroke-width="2"/>\n</svg>\n';
86
+
87
+ // inline-file:/Users/marata/Documents/Work/abledom/src/ui/aligntopright.svg
88
+ var aligntopright_default = '<svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor">\n <rect x="11" y="3" width="6" height="6" stroke-width="2"/>\n</svg>\n';
89
+
90
+ // inline-file:/Users/marata/Documents/Work/abledom/src/ui/alignbottomright.svg
91
+ var alignbottomright_default = '<svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor">\n <rect x="11" y="11" width="6" height="6" stroke-width="2"/>\n</svg>\n';
92
+
93
+ // inline-file:/Users/marata/Documents/Work/abledom/src/ui/alignbottomleft.svg
94
+ var alignbottomleft_default = '<svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor">\n <rect x="3" y="11" width="6" height="6" stroke-width="2"/>\n</svg>\n';
95
+
20
96
  // src/ui/ui.ts
97
+ var pressedClass = "pressed";
98
+ function createTrustedHTML(win, html) {
99
+ var _a, _b;
100
+ const escapeHTMLPolicy = (_b = (_a = win.trustedTypes) == null ? void 0 : _a.createPolicy) == null ? void 0 : _b.call(_a, "forceInner", {
101
+ createHTML: (html2) => html2
102
+ });
103
+ return escapeHTMLPolicy ? escapeHTMLPolicy.createHTML(html) : html;
104
+ }
21
105
  var _NotificationUI = class _NotificationUI {
22
- constructor(element, error) {
106
+ constructor(win, rule) {
107
+ __publicField(this, "_win");
23
108
  __publicField(this, "_wrapper");
24
- var _a;
25
- const wrapper = this._wrapper = document.createElement(
109
+ __publicField(this, "_rule");
110
+ __publicField(this, "_onToggle");
111
+ __publicField(this, "isHidden", false);
112
+ this._win = win;
113
+ this._rule = rule;
114
+ if (!_NotificationUI._notificationsUI) {
115
+ _NotificationUI._notificationsUI = new NotificationsUI(this._win);
116
+ }
117
+ this._wrapper = win.document.createElement(
26
118
  "div"
27
119
  );
28
- const win = element.ownerDocument.defaultView;
29
- if (!win) {
30
- return;
31
- }
32
120
  if (!_NotificationUI._highlight) {
33
121
  _NotificationUI._highlight = new ElementHighlighter(win);
34
122
  }
123
+ _NotificationUI._notificationsUI.addNotification(this);
124
+ }
125
+ static setOnToggle(instance, onToggle) {
126
+ instance._onToggle = onToggle;
127
+ }
128
+ static getElement(instance) {
129
+ return instance._wrapper;
130
+ }
131
+ update(notification) {
132
+ var _a;
133
+ const win = this._win;
134
+ const rule = this._rule;
135
+ const wrapper = this._wrapper;
136
+ const element = notification.element;
35
137
  wrapper.__abledomui = true;
36
- wrapper.innerHTML = `
37
- <div class="abledom-notification-container"><div class="abledom-notification">
138
+ wrapper.innerHTML = createTrustedHTML(
139
+ win,
140
+ `
141
+ <div class="abledom-notification-container"><div class="abledom-notification${rule.type === 2 /* Warning */ ? " abledom-notification_warning" : rule.type === 3 /* Info */ ? " abledom-notification_info" : ""}">
38
142
  <button class="button" title="Log to Console">${log_default}</button>
39
143
  <button class="button" title="Reveal in Elements panel">${reveal_default}</button>
40
- ${error.message}
144
+ ${notification.message}
41
145
  <a href class="button close" href="/" title="Open help" target="_blank">${help_default}</a>
42
146
  <button class="button close" class="close" title="Hide">${close_default}</button>
43
- </div></div>`;
147
+ </div></div>`
148
+ );
44
149
  const container = wrapper.firstElementChild;
45
150
  const buttons = wrapper.querySelectorAll("button");
46
151
  const logButton = buttons[0];
@@ -48,16 +153,18 @@ var _NotificationUI = class _NotificationUI {
48
153
  const closeButton = buttons[2];
49
154
  logButton.onclick = () => {
50
155
  console.error(
51
- "AbleDOM violation: ",
52
- "\nerror:",
53
- error.message,
156
+ "AbleDOM: ",
157
+ "\nmessage:",
158
+ notification.message,
54
159
  "\nelement:",
55
160
  element,
56
- ...error.rel ? ["\nrelative:", error.rel] : []
161
+ ...notification.rel ? ["\nrelative:", notification.rel] : [],
162
+ "\nnotification:",
163
+ notification
57
164
  );
58
165
  };
59
- const hasDevTools = !!((_a = win.__ableDOMDevtools) == null ? void 0 : _a.revealElement);
60
- if (hasDevTools && win.document.body.contains(element)) {
166
+ const hasDevTools = !!((_a = win.__ableDOMDevtools) == null ? void 0 : _a.revealElement) && false;
167
+ if (hasDevTools && element && win.document.body.contains(element)) {
61
168
  revealButton.onclick = () => {
62
169
  var _a2;
63
170
  const revealElement = (_a2 = win.__ableDOMDevtools) == null ? void 0 : _a2.revealElement;
@@ -73,51 +180,239 @@ var _NotificationUI = class _NotificationUI {
73
180
  }
74
181
  closeButton.onclick = () => {
75
182
  var _a2;
76
- wrapper.style.display = "none";
183
+ this.toggle(false);
77
184
  (_a2 = _NotificationUI._highlight) == null ? void 0 : _a2.hide();
78
185
  };
79
186
  container.onmouseover = () => {
80
187
  var _a2;
81
- (_a2 = _NotificationUI._highlight) == null ? void 0 : _a2.highlight(element);
188
+ element && ((_a2 = _NotificationUI._highlight) == null ? void 0 : _a2.highlight(element));
82
189
  };
83
190
  container.onmouseout = () => {
84
191
  var _a2;
85
192
  (_a2 = _NotificationUI._highlight) == null ? void 0 : _a2.hide();
86
193
  };
87
194
  }
88
- static getElement(instance) {
89
- return instance._wrapper;
195
+ toggle(show, initial = false) {
196
+ var _a;
197
+ this.isHidden = !show;
198
+ if (!initial) {
199
+ (_a = this._onToggle) == null ? void 0 : _a.call(this, this, show);
200
+ if (!this._rule.anchored && !show) {
201
+ this.dispose();
202
+ }
203
+ }
204
+ this._wrapper.style.display = show ? "block" : "none";
90
205
  }
91
206
  dispose() {
207
+ var _a;
92
208
  this._wrapper.remove();
209
+ (_a = _NotificationUI._notificationsUI) == null ? void 0 : _a.removeNotification(this);
93
210
  }
94
211
  };
212
+ __publicField(_NotificationUI, "_notificationsUI");
95
213
  __publicField(_NotificationUI, "_highlight");
96
214
  var NotificationUI = _NotificationUI;
97
215
  var NotificationsUI = class {
98
216
  constructor(win) {
99
- // private _window: Window;
217
+ __publicField(this, "_win");
100
218
  __publicField(this, "_container");
219
+ __publicField(this, "_notificationsContainer");
220
+ __publicField(this, "_menuElement");
221
+ __publicField(this, "_notificationCountElement");
222
+ __publicField(this, "_showAllButton");
223
+ __publicField(this, "_hideAllButton");
224
+ __publicField(this, "_alignBottomLeftButton");
225
+ __publicField(this, "_alignTopLeftButton");
226
+ __publicField(this, "_alignTopRightButton");
227
+ __publicField(this, "_alignBottomRightButton");
228
+ __publicField(this, "_isMuted", false);
101
229
  __publicField(this, "_notifications", /* @__PURE__ */ new Set());
102
- const container = this._container = document.createElement("div");
230
+ var _a;
231
+ this._win = win;
232
+ const container = this._container = win.document.createElement("div");
103
233
  container.__abledomui = true;
104
234
  container.id = "abledom-report";
105
- container.innerHTML = `<style>${ui_default}</style>`;
235
+ container.innerHTML = createTrustedHTML(win, `<style>${ui_default}</style>`);
236
+ const notificationsContainer = this._notificationsContainer = win.document.createElement("div");
237
+ notificationsContainer.className = "abledom-notifications-container";
238
+ container.appendChild(notificationsContainer);
239
+ const menuElement = this._menuElement = win.document.createElement("div");
240
+ menuElement.className = "abledom-menu-container";
241
+ menuElement.innerHTML = createTrustedHTML(
242
+ win,
243
+ `<div class="abledom-menu"><span class="notifications-count"></span
244
+ ><button class="button" title="Show all notifications">${showall_default}</button
245
+ ><button class="button" title="Hide all notifications">${hideall_default}</button
246
+ ><button class="button" title="Mute newly appearing notifications">${muteall_default}</button
247
+ ><button class="button align-button align-button-first pressed" title="Attach notifications to bottom left">${alignbottomleft_default}</button
248
+ ><button class="button align-button" title="Attach notifications to top left">${aligntopleft_default}</button
249
+ ><button class="button align-button" title="Attach notifications to top right">${aligntopright_default}</button
250
+ ><button class="button align-button align-button-last" title="Attach notifications to bottom right">${alignbottomright_default}</button
251
+ ></div>`
252
+ );
253
+ const [
254
+ notificationCountElement,
255
+ showAllButton,
256
+ hideAllButton,
257
+ muteButton,
258
+ alignBottomLeftButton,
259
+ alignTopLeftButton,
260
+ alignTopRightButton,
261
+ alignBottomRightButton
262
+ ] = ((_a = menuElement.firstElementChild) == null ? void 0 : _a.childNodes) || [];
263
+ if (notificationCountElement instanceof HTMLSpanElement && showAllButton instanceof HTMLButtonElement && hideAllButton instanceof HTMLButtonElement && muteButton instanceof HTMLButtonElement && alignBottomLeftButton instanceof HTMLButtonElement && alignTopLeftButton instanceof HTMLButtonElement && alignTopRightButton instanceof HTMLButtonElement && alignBottomRightButton instanceof HTMLButtonElement) {
264
+ container.appendChild(menuElement);
265
+ this._notificationCountElement = notificationCountElement;
266
+ this._showAllButton = showAllButton;
267
+ this._hideAllButton = hideAllButton;
268
+ this._alignBottomLeftButton = alignBottomLeftButton;
269
+ this._alignTopLeftButton = alignTopLeftButton;
270
+ this._alignTopRightButton = alignTopRightButton;
271
+ this._alignBottomRightButton = alignBottomRightButton;
272
+ showAllButton.onclick = () => {
273
+ this.showAll();
274
+ };
275
+ hideAllButton.onclick = () => {
276
+ this.hideAll();
277
+ };
278
+ muteButton.onclick = () => {
279
+ const isMuted = this._isMuted = muteButton.classList.toggle(pressedClass);
280
+ if (isMuted) {
281
+ muteButton.setAttribute(
282
+ "title",
283
+ "Unmute newly appearing notifications"
284
+ );
285
+ } else {
286
+ muteButton.setAttribute(
287
+ "title",
288
+ "Mute newly appearing notifications"
289
+ );
290
+ }
291
+ };
292
+ alignBottomLeftButton.onclick = () => {
293
+ this.setUIAlignment("bottom-left" /* BottomLeft */);
294
+ };
295
+ alignBottomRightButton.onclick = () => {
296
+ this.setUIAlignment("bottom-right" /* BottomRight */);
297
+ };
298
+ alignTopLeftButton.onclick = () => {
299
+ this.setUIAlignment("top-left" /* TopLeft */);
300
+ };
301
+ alignTopRightButton.onclick = () => {
302
+ this.setUIAlignment("top-right" /* TopRight */);
303
+ };
304
+ }
106
305
  win.document.body.appendChild(container);
107
306
  }
307
+ setUIAlignment(alignment) {
308
+ var _a, _b, _c, _d, _e, _f, _g, _h;
309
+ (_a = this._alignBottomLeftButton) == null ? void 0 : _a.classList.remove(pressedClass);
310
+ (_b = this._alignBottomRightButton) == null ? void 0 : _b.classList.remove(pressedClass);
311
+ (_c = this._alignTopLeftButton) == null ? void 0 : _c.classList.remove(pressedClass);
312
+ (_d = this._alignTopRightButton) == null ? void 0 : _d.classList.remove(pressedClass);
313
+ this._container.classList.remove(
314
+ "abledom-align-left",
315
+ "abledom-align-right",
316
+ "abledom-align-top",
317
+ "abledom-align-bottom"
318
+ );
319
+ let containerClasses = [];
320
+ let notificationsFirst = false;
321
+ switch (alignment) {
322
+ case "bottom-left" /* BottomLeft */:
323
+ containerClasses = ["abledom-align-left", "abledom-align-bottom"];
324
+ notificationsFirst = true;
325
+ (_e = this._alignBottomLeftButton) == null ? void 0 : _e.classList.add(pressedClass);
326
+ break;
327
+ case "bottom-right" /* BottomRight */:
328
+ containerClasses = ["abledom-align-right", "abledom-align-bottom"];
329
+ notificationsFirst = true;
330
+ (_f = this._alignBottomRightButton) == null ? void 0 : _f.classList.add(pressedClass);
331
+ break;
332
+ case "top-left" /* TopLeft */:
333
+ containerClasses = ["abledom-align-left", "abledom-align-top"];
334
+ (_g = this._alignTopLeftButton) == null ? void 0 : _g.classList.add(pressedClass);
335
+ break;
336
+ case "top-right" /* TopRight */:
337
+ containerClasses = ["abledom-align-right", "abledom-align-top"];
338
+ (_h = this._alignTopRightButton) == null ? void 0 : _h.classList.add(pressedClass);
339
+ break;
340
+ }
341
+ this._container.classList.add(...containerClasses);
342
+ this._container.insertBefore(
343
+ this._notificationsContainer,
344
+ notificationsFirst ? this._menuElement : null
345
+ );
346
+ }
347
+ _setNotificationsCount(count) {
348
+ const countElement = this._notificationCountElement;
349
+ if (countElement && count > 0) {
350
+ countElement.innerHTML = createTrustedHTML(
351
+ this._win,
352
+ `<strong>${count}</strong> notification${count > 1 ? "s" : ""}`
353
+ );
354
+ this._menuElement.style.display = "block";
355
+ } else {
356
+ this._menuElement.style.display = "none";
357
+ }
358
+ }
359
+ _setShowHideButtonsVisibility() {
360
+ const showAllButton = this._showAllButton;
361
+ const hideAllButton = this._hideAllButton;
362
+ if (!showAllButton || !hideAllButton) {
363
+ return;
364
+ }
365
+ let allHidden = true;
366
+ let allVisible = true;
367
+ for (let notification of this._notifications) {
368
+ if (notification.isHidden) {
369
+ allVisible = false;
370
+ } else {
371
+ allHidden = false;
372
+ }
373
+ if (!allHidden && !allVisible) {
374
+ break;
375
+ }
376
+ }
377
+ hideAllButton.style.display = allHidden ? "none" : "block";
378
+ showAllButton.style.display = allVisible ? "none" : "block";
379
+ }
108
380
  addNotification(notification) {
109
381
  if (this._notifications.has(notification)) {
110
382
  return;
111
383
  }
384
+ if (this._isMuted) {
385
+ notification.toggle(false, true);
386
+ }
112
387
  this._notifications.add(notification);
113
- this._container.appendChild(NotificationUI.getElement(notification));
388
+ this._notificationsContainer.appendChild(
389
+ NotificationUI.getElement(notification)
390
+ );
391
+ NotificationUI.setOnToggle(notification, () => {
392
+ this._setShowHideButtonsVisibility();
393
+ });
394
+ this._setNotificationsCount(this._notifications.size);
395
+ this._setShowHideButtonsVisibility();
114
396
  }
115
397
  removeNotification(notification) {
116
398
  if (!this._notifications.has(notification)) {
117
399
  return;
118
400
  }
119
401
  this._notifications.delete(notification);
120
- this._container.removeChild(NotificationUI.getElement(notification));
402
+ this._setNotificationsCount(this._notifications.size);
403
+ this._setShowHideButtonsVisibility();
404
+ }
405
+ hideAll() {
406
+ this._notifications.forEach((notification) => {
407
+ notification.toggle(false);
408
+ });
409
+ this._setShowHideButtonsVisibility();
410
+ }
411
+ showAll() {
412
+ this._notifications.forEach((notification) => {
413
+ notification.toggle(true);
414
+ });
415
+ this._setShowHideButtonsVisibility();
121
416
  }
122
417
  };
123
418
  var ElementHighlighter = class {
@@ -340,91 +635,13 @@ function getStackTrace() {
340
635
  }
341
636
  }
342
637
 
343
- // src/rules/base.ts
344
- var ValidationRule = class {
345
- constructor() {
346
- __publicField(this, "_window");
347
- __publicField(this, "_exceptions", []);
348
- }
349
- static setWindow(instance, window2) {
350
- instance._window = window2;
351
- }
352
- static checkExceptions(instance, element) {
353
- for (const exception of instance._exceptions) {
354
- if (exception(element)) {
355
- return true;
356
- }
357
- }
358
- return false;
359
- }
360
- addException(checkException) {
361
- var _a;
362
- (_a = this._exceptions) == null ? void 0 : _a.push(checkException);
363
- }
364
- removeException(checkException) {
365
- const index = this._exceptions.indexOf(checkException);
366
- if (index >= 0) {
367
- this._exceptions.splice(index, 1);
368
- }
369
- }
370
- /**
371
- * Window is set when the rule is added to the AbleDOM instance.
372
- */
373
- get window() {
374
- return this._window;
375
- }
376
- };
377
-
378
638
  // src/core.ts
379
- var _ValidationErrorReport = class _ValidationErrorReport {
380
- constructor(element, error, onHide) {
381
- this.element = element;
382
- this.error = error;
383
- __publicField(this, "_notification");
384
- __publicField(this, "_onHide");
385
- this._onHide = onHide;
386
- this.report();
387
- }
388
- update(error) {
389
- this.error = error;
390
- this.report();
391
- }
392
- report() {
393
- if (!_ValidationErrorReport._notificationsUI) {
394
- _ValidationErrorReport._notificationsUI = new NotificationsUI(window);
395
- }
396
- let notification = this._notification;
397
- if (notification) {
398
- } else {
399
- notification = this._notification = new NotificationUI(
400
- this.element,
401
- this.error
402
- );
403
- }
404
- _ValidationErrorReport._notificationsUI.addNotification(notification);
405
- }
406
- hide() {
407
- var _a;
408
- (_a = this._onHide) == null ? void 0 : _a.call(this);
409
- }
410
- remove() {
411
- var _a;
412
- if (this._notification) {
413
- (_a = _ValidationErrorReport._notificationsUI) == null ? void 0 : _a.removeNotification(
414
- this._notification
415
- );
416
- delete this._notification;
417
- }
418
- }
419
- };
420
- __publicField(_ValidationErrorReport, "_notificationsUI");
421
- var ValidationErrorReport = _ValidationErrorReport;
422
639
  var AbleDOM = class {
423
640
  constructor(win) {
424
- __publicField(this, "_window");
641
+ __publicField(this, "_win");
425
642
  __publicField(this, "_observer");
426
643
  __publicField(this, "_clearValidationTimeout");
427
- __publicField(this, "_elementsWithErrors", /* @__PURE__ */ new Set());
644
+ __publicField(this, "_elementsWithNotifications", /* @__PURE__ */ new Set());
428
645
  __publicField(this, "_changedElementIds", /* @__PURE__ */ new Set());
429
646
  __publicField(this, "_elementsDependingOnId", /* @__PURE__ */ new Map());
430
647
  __publicField(this, "_dependantIdsByElement", /* @__PURE__ */ new Map());
@@ -439,19 +656,10 @@ var AbleDOM = class {
439
656
  return;
440
657
  }
441
658
  for (const rule of this._rules) {
442
- (_a = rule.focused) == null ? void 0 : _a.call(rule, event).then(
443
- (focusError) => {
444
- if (focusError) {
445
- this._addValidationError(
446
- focusError.element,
447
- rule,
448
- focusError.error
449
- );
450
- }
451
- },
452
- () => {
453
- }
454
- );
659
+ const focusNotification = (_a = rule.focused) == null ? void 0 : _a.call(rule, event);
660
+ if (focusNotification) {
661
+ this._addNotification(rule, focusNotification);
662
+ }
455
663
  }
456
664
  });
457
665
  __publicField(this, "_onFocusOut", (event) => {
@@ -461,22 +669,16 @@ var AbleDOM = class {
461
669
  return;
462
670
  }
463
671
  for (const rule of this._rules) {
464
- (_a = rule.blurred) == null ? void 0 : _a.call(rule, event).then(
465
- (focusError) => {
466
- if (focusError) {
467
- this._addValidationError(
468
- focusError.element,
469
- rule,
470
- focusError.error
471
- );
472
- }
473
- },
474
- () => {
475
- }
476
- );
672
+ const blurNotification = (_a = rule.blurred) == null ? void 0 : _a.call(rule, event);
673
+ if (blurNotification) {
674
+ this._addNotification(rule, blurNotification);
675
+ }
477
676
  }
478
677
  });
479
- this._window = win;
678
+ __publicField(this, "_notifyAsync", (rule, notification) => {
679
+ this._addNotification(rule, notification);
680
+ });
681
+ this._win = win;
480
682
  const _elementsToValidate = /* @__PURE__ */ new Set();
481
683
  const _elementsToRemove = /* @__PURE__ */ new Set();
482
684
  win.document.addEventListener("focusin", this._onFocusIn, true);
@@ -545,7 +747,7 @@ var AbleDOM = class {
545
747
  };
546
748
  function lookUp(node) {
547
749
  for (let n = node; n; n = n.parentNode) {
548
- addTarget(n, false);
750
+ addTarget(n, _elementsToRemove.has(node));
549
751
  }
550
752
  }
551
753
  function findTargets(node, removed) {
@@ -603,49 +805,49 @@ var AbleDOM = class {
603
805
  this._idByElement.delete(element);
604
806
  }
605
807
  }
606
- _addValidationError(element, rule, error) {
607
- if (!error) {
608
- this._removeElementError(element, rule);
808
+ _addNotification(rule, notification) {
809
+ const element = notification == null ? void 0 : notification.element;
810
+ if (!notification) {
811
+ this._removeNotification(element || this._win.document.body, rule);
609
812
  return;
610
813
  }
611
- if (rule.anchored) {
814
+ let notificationUI;
815
+ if (rule.anchored && element) {
612
816
  let abledomOnElement = element.__abledom;
613
817
  if (!abledomOnElement) {
614
818
  abledomOnElement = element.__abledom = {};
615
819
  }
616
- let errors = abledomOnElement.errors;
617
- if (!errors) {
618
- errors = abledomOnElement.errors = /* @__PURE__ */ new Map();
820
+ let notifications = abledomOnElement.notifications;
821
+ if (!notifications) {
822
+ notifications = abledomOnElement.notifications = /* @__PURE__ */ new Map();
619
823
  }
620
- const report = errors.get(rule);
621
- if (report) {
622
- report.update(error);
623
- } else {
624
- errors.set(rule, new ValidationErrorReport(element, error));
824
+ notificationUI = notifications.get(rule);
825
+ if (!notificationUI) {
826
+ notificationUI = new NotificationUI(this._win, rule);
827
+ notifications.set(rule, notificationUI);
625
828
  }
626
- this._elementsWithErrors.add(element);
829
+ this._elementsWithNotifications.add(element);
627
830
  } else {
628
- const report = new ValidationErrorReport(element, error, () => {
629
- report.remove();
630
- });
831
+ notificationUI = new NotificationUI(this._win, rule);
631
832
  }
833
+ notificationUI.update(notification);
632
834
  }
633
- _removeElementError(element, rule) {
835
+ _removeNotification(element, rule) {
634
836
  var _a;
635
837
  if (!rule.anchored) {
636
838
  return;
637
839
  }
638
- const errors = (_a = element.__abledom) == null ? void 0 : _a.errors;
639
- if (!errors) {
840
+ const notifications = (_a = element.__abledom) == null ? void 0 : _a.notifications;
841
+ if (!notifications) {
640
842
  return;
641
843
  }
642
- const report = errors.get(rule);
643
- if (report) {
644
- report.remove();
645
- errors.delete(rule);
844
+ const notification = notifications.get(rule);
845
+ if (notification) {
846
+ notification.dispose();
847
+ notifications.delete(rule);
646
848
  }
647
- if (errors.size === 0) {
648
- this._elementsWithErrors.delete(element);
849
+ if (notifications.size === 0) {
850
+ this._elementsWithNotifications.delete(element);
649
851
  delete element.__abledom;
650
852
  }
651
853
  }
@@ -660,26 +862,26 @@ var AbleDOM = class {
660
862
  }
661
863
  elements.forEach((element) => {
662
864
  var _a, _b, _c, _d, _e;
663
- if (isAccessibilityAffectingElement(element) || ((_a = element.__abledom) == null ? void 0 : _a.errors)) {
865
+ if (isAccessibilityAffectingElement(element) || ((_a = element.__abledom) == null ? void 0 : _a.notifications)) {
664
866
  const dependsOnIds = /* @__PURE__ */ new Set();
665
867
  for (const rule of this._rules) {
666
- if (((_b = rule.accept) == null ? void 0 : _b.call(rule, element)) === false) {
868
+ if (!rule.validate || ((_b = rule.accept) == null ? void 0 : _b.call(rule, element)) === false) {
667
869
  continue;
668
870
  }
669
871
  if (ValidationRule.checkExceptions(rule, element)) {
670
872
  continue;
671
873
  }
672
874
  const validationResult = (_c = rule.validate) == null ? void 0 : _c.call(rule, element);
673
- if (validationResult) {
674
- this._addValidationError(element, rule, validationResult.error);
875
+ if (validationResult == null ? void 0 : validationResult.notification) {
876
+ this._addNotification(rule, validationResult.notification);
675
877
  const ids = validationResult.dependsOnIds;
676
878
  if (ids) {
677
879
  for (const id of ids) {
678
880
  dependsOnIds.add(id);
679
881
  }
680
882
  }
681
- } else if ((_e = (_d = element.__abledom) == null ? void 0 : _d.errors) == null ? void 0 : _e.has(rule)) {
682
- this._removeElementError(element, rule);
883
+ } else if ((_e = (_d = element.__abledom) == null ? void 0 : _d.notifications) == null ? void 0 : _e.has(rule)) {
884
+ this._removeNotification(element, rule);
683
885
  }
684
886
  }
685
887
  this._processElementDependingOnIds(
@@ -731,8 +933,8 @@ var AbleDOM = class {
731
933
  _remove(elements) {
732
934
  elements.forEach((element) => {
733
935
  var _a, _b;
734
- const rules = [...((_b = (_a = element.__abledom) == null ? void 0 : _a.errors) == null ? void 0 : _b.keys()) || []];
735
- rules.forEach((rule) => this._removeElementError(element, rule));
936
+ const rules = [...((_b = (_a = element.__abledom) == null ? void 0 : _a.notifications) == null ? void 0 : _b.keys()) || []];
937
+ rules.forEach((rule) => this._removeNotification(element, rule));
736
938
  });
737
939
  }
738
940
  addRule(rule) {
@@ -754,23 +956,24 @@ var AbleDOM = class {
754
956
  }
755
957
  this._isStarted = true;
756
958
  for (const rule of this._rules) {
757
- ValidationRule.setWindow(rule, this._window);
959
+ ValidationRule.init(rule, this._win, this._notifyAsync);
758
960
  (_a = rule.start) == null ? void 0 : _a.call(rule);
759
961
  }
760
962
  (_b = this._startFunc) == null ? void 0 : _b.call(this);
761
963
  }
762
964
  dispose() {
763
965
  var _a, _b;
764
- this._window.document.addEventListener("focusin", this._onFocusIn, true);
765
- this._window.document.addEventListener("focusout", this._onFocusOut, true);
766
- this._remove(this._elementsWithErrors);
767
- this._elementsWithErrors.clear();
966
+ this._win.document.addEventListener("focusin", this._onFocusIn, true);
967
+ this._win.document.addEventListener("focusout", this._onFocusOut, true);
968
+ this._remove(this._elementsWithNotifications);
969
+ this._elementsWithNotifications.clear();
768
970
  this._dependantIdsByElement.clear();
769
971
  this._elementsDependingOnId.clear();
770
972
  this._idByElement.clear();
771
973
  (_a = this._clearValidationTimeout) == null ? void 0 : _a.call(this);
772
974
  for (const rule of this._rules) {
773
975
  (_b = rule.stop) == null ? void 0 : _b.call(rule);
976
+ ValidationRule.dispose(rule);
774
977
  }
775
978
  this._rules = [];
776
979
  if (this._startFunc) {
@@ -785,6 +988,7 @@ var AbleDOM = class {
785
988
  var AtomicRule = class extends ValidationRule {
786
989
  constructor() {
787
990
  super(...arguments);
991
+ __publicField(this, "type", 1 /* Error */);
788
992
  __publicField(this, "name", "atomic");
789
993
  __publicField(this, "anchored", true);
790
994
  }
@@ -818,9 +1022,10 @@ var AtomicRule = class extends ValidationRule {
818
1022
  ).snapshotItem(0);
819
1023
  if (parentAtomic) {
820
1024
  return {
821
- error: {
1025
+ notification: {
822
1026
  id: "focusable-in-atomic",
823
1027
  message: "Focusable element inside atomic focusable.",
1028
+ element,
824
1029
  rel: parentAtomic
825
1030
  }
826
1031
  };
@@ -847,6 +1052,7 @@ var _keyboardEditableInputTypes = /* @__PURE__ */ new Set([
847
1052
  var FocusableElementLabelRule = class extends ValidationRule {
848
1053
  constructor() {
849
1054
  super(...arguments);
1055
+ __publicField(this, "type", 1 /* Error */);
850
1056
  __publicField(this, "name", "FocusableElementLabelRule");
851
1057
  __publicField(this, "anchored", true);
852
1058
  }
@@ -950,9 +1156,10 @@ var FocusableElementLabelRule = class extends ValidationRule {
950
1156
  }
951
1157
  }
952
1158
  return {
953
- error: isElementVisible(element) ? {
1159
+ notification: isElementVisible(element) ? {
954
1160
  id: "focusable-element-label",
955
- message: "Focusable element must have a non-empty text label."
1161
+ message: "Focusable element must have a non-empty text label.",
1162
+ element
956
1163
  } : void 0,
957
1164
  dependsOnIds: new Set(labelledByValues)
958
1165
  };
@@ -963,6 +1170,7 @@ var FocusableElementLabelRule = class extends ValidationRule {
963
1170
  var ExistingIdRule = class extends ValidationRule {
964
1171
  constructor() {
965
1172
  super(...arguments);
1173
+ __publicField(this, "type", 1 /* Error */);
966
1174
  __publicField(this, "name", "existing-id");
967
1175
  __publicField(this, "anchored", true);
968
1176
  }
@@ -987,9 +1195,10 @@ var ExistingIdRule = class extends ValidationRule {
987
1195
  }
988
1196
  }
989
1197
  return {
990
- error: {
1198
+ notification: {
991
1199
  id: "missing-id",
992
- message: `Elements with referenced ids do not extist.`
1200
+ message: `Elements with referenced ids do not extist.`,
1201
+ element
993
1202
  },
994
1203
  dependsOnIds: new Set(ids)
995
1204
  };
@@ -1000,6 +1209,7 @@ var ExistingIdRule = class extends ValidationRule {
1000
1209
  var FocusLostRule = class extends ValidationRule {
1001
1210
  constructor() {
1002
1211
  super(...arguments);
1212
+ __publicField(this, "type", 1 /* Error */);
1003
1213
  __publicField(this, "name", "focus-lost");
1004
1214
  __publicField(this, "anchored", false);
1005
1215
  __publicField(this, "_focusLostTimeout", 2e3);
@@ -1009,6 +1219,8 @@ var FocusLostRule = class extends ValidationRule {
1009
1219
  __publicField(this, "_focusedElementPosition");
1010
1220
  __publicField(this, "_lastFocusStack");
1011
1221
  __publicField(this, "_lastBlurStack");
1222
+ __publicField(this, "_mouseEventTimer");
1223
+ __publicField(this, "_releaseMouseEvent");
1012
1224
  }
1013
1225
  _serializeElementPosition(element) {
1014
1226
  const position = [];
@@ -1022,7 +1234,7 @@ var FocusLostRule = class extends ValidationRule {
1022
1234
  }
1023
1235
  return position;
1024
1236
  }
1025
- async focused(event) {
1237
+ focused(event) {
1026
1238
  var _a;
1027
1239
  const target = event.target;
1028
1240
  (_a = this._clearScheduledFocusLost) == null ? void 0 : _a.call(this);
@@ -1033,53 +1245,71 @@ var FocusLostRule = class extends ValidationRule {
1033
1245
  }
1034
1246
  return null;
1035
1247
  }
1036
- async blurred(event) {
1248
+ blurred(event) {
1037
1249
  var _a;
1038
1250
  const target = event.target;
1039
1251
  const win = this.window;
1040
1252
  (_a = this._clearScheduledFocusLost) == null ? void 0 : _a.call(this);
1041
- if (!target || !win || event.relatedTarget) {
1253
+ if (!target || !win || event.relatedTarget || this._mouseEventTimer) {
1042
1254
  return null;
1043
1255
  }
1044
- let focusLostTimer;
1045
- let rejectPromise;
1046
1256
  const targetPosition = this._focusedElement === target ? this._focusedElementPosition : void 0;
1047
1257
  this._lastBlurStack = getStackTrace();
1048
1258
  this._focusedElement = void 0;
1049
1259
  this._focusedElementPosition = void 0;
1260
+ const focusLostTimer = win.setTimeout(() => {
1261
+ delete this._clearScheduledFocusLost;
1262
+ if (win.document.body && (!win.document.activeElement || win.document.activeElement === win.document.body) && (!win.document.body.contains(target) || !isElementVisible(target))) {
1263
+ this.notify({
1264
+ element: target,
1265
+ id: "focus-lost",
1266
+ message: "Focus lost.",
1267
+ stack: this._lastBlurStack,
1268
+ relStack: this._lastFocusStack,
1269
+ position: targetPosition || []
1270
+ });
1271
+ }
1272
+ }, this._focusLostTimeout);
1050
1273
  this._clearScheduledFocusLost = () => {
1051
1274
  delete this._clearScheduledFocusLost;
1052
- rejectPromise == null ? void 0 : rejectPromise();
1053
- if (focusLostTimer) {
1054
- win.clearTimeout(focusLostTimer);
1055
- focusLostTimer = void 0;
1275
+ win.clearTimeout(focusLostTimer);
1276
+ };
1277
+ return null;
1278
+ }
1279
+ start() {
1280
+ const win = this.window;
1281
+ if (!win) {
1282
+ return;
1283
+ }
1284
+ const onMouseEvent = () => {
1285
+ if (!this._mouseEventTimer) {
1286
+ this._mouseEventTimer = win.setTimeout(() => {
1287
+ this._mouseEventTimer = void 0;
1288
+ }, 0);
1056
1289
  }
1057
1290
  };
1058
- return new Promise((resolve, reject) => {
1059
- rejectPromise = () => {
1060
- rejectPromise = void 0;
1061
- reject();
1062
- };
1063
- focusLostTimer = win.setTimeout(() => {
1064
- focusLostTimer = void 0;
1065
- rejectPromise = void 0;
1066
- delete this._clearScheduledFocusLost;
1067
- if (win.document.body && (!win.document.activeElement || win.document.activeElement === win.document.body) && (!win.document.body.contains(target) || !isElementVisible(target))) {
1068
- resolve({
1069
- element: target,
1070
- position: targetPosition || [],
1071
- error: {
1072
- id: "focus-lost",
1073
- message: "Focus lost.",
1074
- stack: this._lastBlurStack,
1075
- relStack: this._lastFocusStack
1076
- }
1077
- });
1078
- } else {
1079
- resolve(null);
1080
- }
1081
- }, this._focusLostTimeout);
1082
- });
1291
+ win.addEventListener("mousedown", onMouseEvent, true);
1292
+ win.addEventListener("mouseup", onMouseEvent, true);
1293
+ win.addEventListener("mousemove", onMouseEvent, true);
1294
+ this._releaseMouseEvent = () => {
1295
+ delete this._releaseMouseEvent;
1296
+ if (this._mouseEventTimer) {
1297
+ win.clearTimeout(this._mouseEventTimer);
1298
+ delete this._mouseEventTimer;
1299
+ }
1300
+ win.removeEventListener("mousedown", onMouseEvent, true);
1301
+ win.removeEventListener("mouseup", onMouseEvent, true);
1302
+ win.removeEventListener("mousemove", onMouseEvent, true);
1303
+ };
1304
+ }
1305
+ stop() {
1306
+ var _a, _b;
1307
+ (_a = this._releaseMouseEvent) == null ? void 0 : _a.call(this);
1308
+ (_b = this._clearScheduledFocusLost) == null ? void 0 : _b.call(this);
1309
+ this._focusedElement = void 0;
1310
+ this._focusedElementPosition = void 0;
1311
+ this._lastFocusStack = void 0;
1312
+ this._lastBlurStack = void 0;
1083
1313
  }
1084
1314
  };
1085
1315
 
@@ -1087,53 +1317,96 @@ var FocusLostRule = class extends ValidationRule {
1087
1317
  var BadFocusRule = class extends ValidationRule {
1088
1318
  constructor() {
1089
1319
  super(...arguments);
1320
+ __publicField(this, "type", 1 /* Error */);
1090
1321
  __publicField(this, "name", "bad-focus");
1091
1322
  __publicField(this, "anchored", false);
1092
1323
  __publicField(this, "_lastFocusStack");
1093
1324
  __publicField(this, "_lastBlurStack");
1094
- __publicField(this, "_reject");
1325
+ __publicField(this, "_clearCheckTimer");
1095
1326
  }
1096
- async focused() {
1097
- var _a;
1327
+ focused() {
1098
1328
  this._lastFocusStack = getStackTrace();
1099
- (_a = this._reject) == null ? void 0 : _a.call(this);
1100
1329
  return null;
1101
1330
  }
1102
- async blurred() {
1331
+ blurred() {
1103
1332
  var _a;
1104
- (_a = this._reject) == null ? void 0 : _a.call(this);
1105
1333
  const win = this.window;
1106
1334
  if (!win) {
1107
1335
  return null;
1108
1336
  }
1109
1337
  this._lastBlurStack = getStackTrace();
1110
- return new Promise((resolve, reject) => {
1111
- let checkTimer;
1112
- this._reject = () => {
1113
- if (checkTimer) {
1114
- win.clearTimeout(checkTimer);
1115
- checkTimer = void 0;
1116
- }
1117
- this._reject = void 0;
1118
- reject();
1119
- };
1120
- checkTimer = win.setTimeout(() => {
1121
- checkTimer = void 0;
1122
- this._reject = void 0;
1123
- if (document.activeElement && !isElementVisible(document.activeElement)) {
1124
- resolve({
1125
- element: document.activeElement,
1126
- error: {
1127
- id: "bad-focus",
1128
- message: "Focused stolen by invisible element.",
1129
- stack: this._lastBlurStack,
1130
- relStack: this._lastFocusStack
1131
- }
1132
- });
1133
- } else {
1134
- resolve(null);
1135
- }
1136
- }, 100);
1338
+ (_a = this._clearCheckTimer) == null ? void 0 : _a.call(this);
1339
+ const checkTimer = win.setTimeout(() => {
1340
+ delete this._clearCheckTimer;
1341
+ if (document.activeElement && !isElementVisible(document.activeElement)) {
1342
+ this.notify({
1343
+ id: "bad-focus",
1344
+ message: "Focused stolen by invisible element.",
1345
+ element: document.activeElement,
1346
+ stack: this._lastBlurStack,
1347
+ relStack: this._lastFocusStack
1348
+ });
1349
+ }
1350
+ }, 100);
1351
+ this._clearCheckTimer = () => {
1352
+ delete this._clearCheckTimer;
1353
+ win.clearTimeout(checkTimer);
1354
+ };
1355
+ return null;
1356
+ }
1357
+ stop() {
1358
+ var _a;
1359
+ (_a = this._clearCheckTimer) == null ? void 0 : _a.call(this);
1360
+ this._clearCheckTimer = void 0;
1361
+ this._lastFocusStack = void 0;
1362
+ this._lastBlurStack = void 0;
1363
+ }
1364
+ };
1365
+
1366
+ // src/rules/find.ts
1367
+ var FindElementRule = class extends ValidationRule {
1368
+ constructor() {
1369
+ super(...arguments);
1370
+ __publicField(this, "type", 2 /* Warning */);
1371
+ __publicField(this, "name", "find-element");
1372
+ __publicField(this, "anchored", true);
1373
+ __publicField(this, "_conditions", {});
1374
+ }
1375
+ addCondition(name, condition) {
1376
+ this._conditions[name] = condition;
1377
+ }
1378
+ removeCondition(name) {
1379
+ delete this._conditions[name];
1380
+ }
1381
+ validate(element) {
1382
+ for (const name of Object.keys(this._conditions)) {
1383
+ if (this._conditions[name](element)) {
1384
+ return {
1385
+ notification: {
1386
+ id: "find-element",
1387
+ message: `Element found: ${name}.`,
1388
+ element
1389
+ }
1390
+ };
1391
+ }
1392
+ }
1393
+ return null;
1394
+ }
1395
+ };
1396
+
1397
+ // src/rules/notify.ts
1398
+ var CustomNotifyRule = class extends ValidationRule {
1399
+ constructor() {
1400
+ super(...arguments);
1401
+ __publicField(this, "type", 3 /* Info */);
1402
+ __publicField(this, "name", "custom-notify");
1403
+ __publicField(this, "anchored", false);
1404
+ }
1405
+ customNotify(message, element) {
1406
+ this.notify({
1407
+ id: "custom-notify",
1408
+ message,
1409
+ element
1137
1410
  });
1138
1411
  }
1139
1412
  };
@@ -1141,10 +1414,18 @@ export {
1141
1414
  AbleDOM,
1142
1415
  AtomicRule,
1143
1416
  BadFocusRule,
1417
+ CustomNotifyRule,
1144
1418
  ExistingIdRule,
1419
+ FindElementRule,
1145
1420
  FocusLostRule,
1146
1421
  FocusableElementLabelRule,
1147
- ValidationRule
1422
+ ValidationRule,
1423
+ ValidationRuleType,
1424
+ hasAccessibilityAttribute,
1425
+ isAccessibilityAffectingElement,
1426
+ isDisplayNone,
1427
+ isElementVisible,
1428
+ matchesSelector
1148
1429
  };
1149
1430
  /*!
1150
1431
  * Copyright (c) Microsoft Corporation. All rights reserved.