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/index.js CHANGED
@@ -25,15 +25,78 @@ __export(index_exports, {
25
25
  AbleDOM: () => AbleDOM,
26
26
  AtomicRule: () => AtomicRule,
27
27
  BadFocusRule: () => BadFocusRule,
28
+ CustomNotifyRule: () => CustomNotifyRule,
28
29
  ExistingIdRule: () => ExistingIdRule,
30
+ FindElementRule: () => FindElementRule,
29
31
  FocusLostRule: () => FocusLostRule,
30
32
  FocusableElementLabelRule: () => FocusableElementLabelRule,
31
- ValidationRule: () => ValidationRule
33
+ ValidationRule: () => ValidationRule,
34
+ ValidationRuleType: () => ValidationRuleType,
35
+ hasAccessibilityAttribute: () => hasAccessibilityAttribute,
36
+ isAccessibilityAffectingElement: () => isAccessibilityAffectingElement,
37
+ isDisplayNone: () => isDisplayNone,
38
+ isElementVisible: () => isElementVisible,
39
+ matchesSelector: () => matchesSelector
32
40
  });
33
41
  module.exports = __toCommonJS(index_exports);
34
42
 
43
+ // src/rules/base.ts
44
+ var ValidationRuleType = /* @__PURE__ */ ((ValidationRuleType2) => {
45
+ ValidationRuleType2[ValidationRuleType2["Error"] = 1] = "Error";
46
+ ValidationRuleType2[ValidationRuleType2["Warning"] = 2] = "Warning";
47
+ ValidationRuleType2[ValidationRuleType2["Info"] = 3] = "Info";
48
+ return ValidationRuleType2;
49
+ })(ValidationRuleType || {});
50
+ var ValidationRule = class {
51
+ constructor() {
52
+ __publicField(this, "_window");
53
+ __publicField(this, "_exceptions", []);
54
+ __publicField(this, "_onNotification");
55
+ }
56
+ static init(instance, window, onNotification) {
57
+ instance._window = window;
58
+ instance._onNotification = onNotification;
59
+ }
60
+ static dispose(instance) {
61
+ instance.dispose();
62
+ }
63
+ static checkExceptions(instance, element) {
64
+ for (const exception of instance._exceptions) {
65
+ if (exception(element)) {
66
+ return true;
67
+ }
68
+ }
69
+ return false;
70
+ }
71
+ dispose() {
72
+ this._window = void 0;
73
+ this._onNotification = void 0;
74
+ this._exceptions = [];
75
+ }
76
+ addException(checkException) {
77
+ var _a;
78
+ (_a = this._exceptions) == null ? void 0 : _a.push(checkException);
79
+ }
80
+ removeException(checkException) {
81
+ const index = this._exceptions.indexOf(checkException);
82
+ if (index >= 0) {
83
+ this._exceptions.splice(index, 1);
84
+ }
85
+ }
86
+ /**
87
+ * Window is set when the rule is added to the AbleDOM instance.
88
+ */
89
+ get window() {
90
+ return this._window;
91
+ }
92
+ notify(notification) {
93
+ var _a;
94
+ (_a = this._onNotification) == null ? void 0 : _a.call(this, this, notification);
95
+ }
96
+ };
97
+
35
98
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/ui.css
36
- 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";
99
+ 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";
37
100
 
38
101
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/close.svg
39
102
  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';
@@ -47,30 +110,80 @@ var log_default = '<svg width="20" height="20" viewBox="0 0 24 24" fill="none" s
47
110
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/reveal.svg
48
111
  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>';
49
112
 
113
+ // inline-file:/Users/marata/Documents/Work/abledom/src/ui/hideall.svg
114
+ 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';
115
+
116
+ // inline-file:/Users/marata/Documents/Work/abledom/src/ui/muteall.svg
117
+ 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';
118
+
119
+ // inline-file:/Users/marata/Documents/Work/abledom/src/ui/showall.svg
120
+ 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';
121
+
122
+ // inline-file:/Users/marata/Documents/Work/abledom/src/ui/aligntopleft.svg
123
+ 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';
124
+
125
+ // inline-file:/Users/marata/Documents/Work/abledom/src/ui/aligntopright.svg
126
+ 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';
127
+
128
+ // inline-file:/Users/marata/Documents/Work/abledom/src/ui/alignbottomright.svg
129
+ 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';
130
+
131
+ // inline-file:/Users/marata/Documents/Work/abledom/src/ui/alignbottomleft.svg
132
+ 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';
133
+
50
134
  // src/ui/ui.ts
135
+ var pressedClass = "pressed";
136
+ function createTrustedHTML(win, html) {
137
+ var _a, _b;
138
+ const escapeHTMLPolicy = (_b = (_a = win.trustedTypes) == null ? void 0 : _a.createPolicy) == null ? void 0 : _b.call(_a, "forceInner", {
139
+ createHTML: (html2) => html2
140
+ });
141
+ return escapeHTMLPolicy ? escapeHTMLPolicy.createHTML(html) : html;
142
+ }
51
143
  var _NotificationUI = class _NotificationUI {
52
- constructor(element, error) {
144
+ constructor(win, rule) {
145
+ __publicField(this, "_win");
53
146
  __publicField(this, "_wrapper");
54
- var _a;
55
- const wrapper = this._wrapper = document.createElement(
147
+ __publicField(this, "_rule");
148
+ __publicField(this, "_onToggle");
149
+ __publicField(this, "isHidden", false);
150
+ this._win = win;
151
+ this._rule = rule;
152
+ if (!_NotificationUI._notificationsUI) {
153
+ _NotificationUI._notificationsUI = new NotificationsUI(this._win);
154
+ }
155
+ this._wrapper = win.document.createElement(
56
156
  "div"
57
157
  );
58
- const win = element.ownerDocument.defaultView;
59
- if (!win) {
60
- return;
61
- }
62
158
  if (!_NotificationUI._highlight) {
63
159
  _NotificationUI._highlight = new ElementHighlighter(win);
64
160
  }
161
+ _NotificationUI._notificationsUI.addNotification(this);
162
+ }
163
+ static setOnToggle(instance, onToggle) {
164
+ instance._onToggle = onToggle;
165
+ }
166
+ static getElement(instance) {
167
+ return instance._wrapper;
168
+ }
169
+ update(notification) {
170
+ var _a;
171
+ const win = this._win;
172
+ const rule = this._rule;
173
+ const wrapper = this._wrapper;
174
+ const element = notification.element;
65
175
  wrapper.__abledomui = true;
66
- wrapper.innerHTML = `
67
- <div class="abledom-notification-container"><div class="abledom-notification">
176
+ wrapper.innerHTML = createTrustedHTML(
177
+ win,
178
+ `
179
+ <div class="abledom-notification-container"><div class="abledom-notification${rule.type === 2 /* Warning */ ? " abledom-notification_warning" : rule.type === 3 /* Info */ ? " abledom-notification_info" : ""}">
68
180
  <button class="button" title="Log to Console">${log_default}</button>
69
181
  <button class="button" title="Reveal in Elements panel">${reveal_default}</button>
70
- ${error.message}
182
+ ${notification.message}
71
183
  <a href class="button close" href="/" title="Open help" target="_blank">${help_default}</a>
72
184
  <button class="button close" class="close" title="Hide">${close_default}</button>
73
- </div></div>`;
185
+ </div></div>`
186
+ );
74
187
  const container = wrapper.firstElementChild;
75
188
  const buttons = wrapper.querySelectorAll("button");
76
189
  const logButton = buttons[0];
@@ -78,16 +191,18 @@ var _NotificationUI = class _NotificationUI {
78
191
  const closeButton = buttons[2];
79
192
  logButton.onclick = () => {
80
193
  console.error(
81
- "AbleDOM violation: ",
82
- "\nerror:",
83
- error.message,
194
+ "AbleDOM: ",
195
+ "\nmessage:",
196
+ notification.message,
84
197
  "\nelement:",
85
198
  element,
86
- ...error.rel ? ["\nrelative:", error.rel] : []
199
+ ...notification.rel ? ["\nrelative:", notification.rel] : [],
200
+ "\nnotification:",
201
+ notification
87
202
  );
88
203
  };
89
- const hasDevTools = !!((_a = win.__ableDOMDevtools) == null ? void 0 : _a.revealElement);
90
- if (hasDevTools && win.document.body.contains(element)) {
204
+ const hasDevTools = !!((_a = win.__ableDOMDevtools) == null ? void 0 : _a.revealElement) && false;
205
+ if (hasDevTools && element && win.document.body.contains(element)) {
91
206
  revealButton.onclick = () => {
92
207
  var _a2;
93
208
  const revealElement = (_a2 = win.__ableDOMDevtools) == null ? void 0 : _a2.revealElement;
@@ -103,51 +218,239 @@ var _NotificationUI = class _NotificationUI {
103
218
  }
104
219
  closeButton.onclick = () => {
105
220
  var _a2;
106
- wrapper.style.display = "none";
221
+ this.toggle(false);
107
222
  (_a2 = _NotificationUI._highlight) == null ? void 0 : _a2.hide();
108
223
  };
109
224
  container.onmouseover = () => {
110
225
  var _a2;
111
- (_a2 = _NotificationUI._highlight) == null ? void 0 : _a2.highlight(element);
226
+ element && ((_a2 = _NotificationUI._highlight) == null ? void 0 : _a2.highlight(element));
112
227
  };
113
228
  container.onmouseout = () => {
114
229
  var _a2;
115
230
  (_a2 = _NotificationUI._highlight) == null ? void 0 : _a2.hide();
116
231
  };
117
232
  }
118
- static getElement(instance) {
119
- return instance._wrapper;
233
+ toggle(show, initial = false) {
234
+ var _a;
235
+ this.isHidden = !show;
236
+ if (!initial) {
237
+ (_a = this._onToggle) == null ? void 0 : _a.call(this, this, show);
238
+ if (!this._rule.anchored && !show) {
239
+ this.dispose();
240
+ }
241
+ }
242
+ this._wrapper.style.display = show ? "block" : "none";
120
243
  }
121
244
  dispose() {
245
+ var _a;
122
246
  this._wrapper.remove();
247
+ (_a = _NotificationUI._notificationsUI) == null ? void 0 : _a.removeNotification(this);
123
248
  }
124
249
  };
250
+ __publicField(_NotificationUI, "_notificationsUI");
125
251
  __publicField(_NotificationUI, "_highlight");
126
252
  var NotificationUI = _NotificationUI;
127
253
  var NotificationsUI = class {
128
254
  constructor(win) {
129
- // private _window: Window;
255
+ __publicField(this, "_win");
130
256
  __publicField(this, "_container");
257
+ __publicField(this, "_notificationsContainer");
258
+ __publicField(this, "_menuElement");
259
+ __publicField(this, "_notificationCountElement");
260
+ __publicField(this, "_showAllButton");
261
+ __publicField(this, "_hideAllButton");
262
+ __publicField(this, "_alignBottomLeftButton");
263
+ __publicField(this, "_alignTopLeftButton");
264
+ __publicField(this, "_alignTopRightButton");
265
+ __publicField(this, "_alignBottomRightButton");
266
+ __publicField(this, "_isMuted", false);
131
267
  __publicField(this, "_notifications", /* @__PURE__ */ new Set());
132
- const container = this._container = document.createElement("div");
268
+ var _a;
269
+ this._win = win;
270
+ const container = this._container = win.document.createElement("div");
133
271
  container.__abledomui = true;
134
272
  container.id = "abledom-report";
135
- container.innerHTML = `<style>${ui_default}</style>`;
273
+ container.innerHTML = createTrustedHTML(win, `<style>${ui_default}</style>`);
274
+ const notificationsContainer = this._notificationsContainer = win.document.createElement("div");
275
+ notificationsContainer.className = "abledom-notifications-container";
276
+ container.appendChild(notificationsContainer);
277
+ const menuElement = this._menuElement = win.document.createElement("div");
278
+ menuElement.className = "abledom-menu-container";
279
+ menuElement.innerHTML = createTrustedHTML(
280
+ win,
281
+ `<div class="abledom-menu"><span class="notifications-count"></span
282
+ ><button class="button" title="Show all notifications">${showall_default}</button
283
+ ><button class="button" title="Hide all notifications">${hideall_default}</button
284
+ ><button class="button" title="Mute newly appearing notifications">${muteall_default}</button
285
+ ><button class="button align-button align-button-first pressed" title="Attach notifications to bottom left">${alignbottomleft_default}</button
286
+ ><button class="button align-button" title="Attach notifications to top left">${aligntopleft_default}</button
287
+ ><button class="button align-button" title="Attach notifications to top right">${aligntopright_default}</button
288
+ ><button class="button align-button align-button-last" title="Attach notifications to bottom right">${alignbottomright_default}</button
289
+ ></div>`
290
+ );
291
+ const [
292
+ notificationCountElement,
293
+ showAllButton,
294
+ hideAllButton,
295
+ muteButton,
296
+ alignBottomLeftButton,
297
+ alignTopLeftButton,
298
+ alignTopRightButton,
299
+ alignBottomRightButton
300
+ ] = ((_a = menuElement.firstElementChild) == null ? void 0 : _a.childNodes) || [];
301
+ 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) {
302
+ container.appendChild(menuElement);
303
+ this._notificationCountElement = notificationCountElement;
304
+ this._showAllButton = showAllButton;
305
+ this._hideAllButton = hideAllButton;
306
+ this._alignBottomLeftButton = alignBottomLeftButton;
307
+ this._alignTopLeftButton = alignTopLeftButton;
308
+ this._alignTopRightButton = alignTopRightButton;
309
+ this._alignBottomRightButton = alignBottomRightButton;
310
+ showAllButton.onclick = () => {
311
+ this.showAll();
312
+ };
313
+ hideAllButton.onclick = () => {
314
+ this.hideAll();
315
+ };
316
+ muteButton.onclick = () => {
317
+ const isMuted = this._isMuted = muteButton.classList.toggle(pressedClass);
318
+ if (isMuted) {
319
+ muteButton.setAttribute(
320
+ "title",
321
+ "Unmute newly appearing notifications"
322
+ );
323
+ } else {
324
+ muteButton.setAttribute(
325
+ "title",
326
+ "Mute newly appearing notifications"
327
+ );
328
+ }
329
+ };
330
+ alignBottomLeftButton.onclick = () => {
331
+ this.setUIAlignment("bottom-left" /* BottomLeft */);
332
+ };
333
+ alignBottomRightButton.onclick = () => {
334
+ this.setUIAlignment("bottom-right" /* BottomRight */);
335
+ };
336
+ alignTopLeftButton.onclick = () => {
337
+ this.setUIAlignment("top-left" /* TopLeft */);
338
+ };
339
+ alignTopRightButton.onclick = () => {
340
+ this.setUIAlignment("top-right" /* TopRight */);
341
+ };
342
+ }
136
343
  win.document.body.appendChild(container);
137
344
  }
345
+ setUIAlignment(alignment) {
346
+ var _a, _b, _c, _d, _e, _f, _g, _h;
347
+ (_a = this._alignBottomLeftButton) == null ? void 0 : _a.classList.remove(pressedClass);
348
+ (_b = this._alignBottomRightButton) == null ? void 0 : _b.classList.remove(pressedClass);
349
+ (_c = this._alignTopLeftButton) == null ? void 0 : _c.classList.remove(pressedClass);
350
+ (_d = this._alignTopRightButton) == null ? void 0 : _d.classList.remove(pressedClass);
351
+ this._container.classList.remove(
352
+ "abledom-align-left",
353
+ "abledom-align-right",
354
+ "abledom-align-top",
355
+ "abledom-align-bottom"
356
+ );
357
+ let containerClasses = [];
358
+ let notificationsFirst = false;
359
+ switch (alignment) {
360
+ case "bottom-left" /* BottomLeft */:
361
+ containerClasses = ["abledom-align-left", "abledom-align-bottom"];
362
+ notificationsFirst = true;
363
+ (_e = this._alignBottomLeftButton) == null ? void 0 : _e.classList.add(pressedClass);
364
+ break;
365
+ case "bottom-right" /* BottomRight */:
366
+ containerClasses = ["abledom-align-right", "abledom-align-bottom"];
367
+ notificationsFirst = true;
368
+ (_f = this._alignBottomRightButton) == null ? void 0 : _f.classList.add(pressedClass);
369
+ break;
370
+ case "top-left" /* TopLeft */:
371
+ containerClasses = ["abledom-align-left", "abledom-align-top"];
372
+ (_g = this._alignTopLeftButton) == null ? void 0 : _g.classList.add(pressedClass);
373
+ break;
374
+ case "top-right" /* TopRight */:
375
+ containerClasses = ["abledom-align-right", "abledom-align-top"];
376
+ (_h = this._alignTopRightButton) == null ? void 0 : _h.classList.add(pressedClass);
377
+ break;
378
+ }
379
+ this._container.classList.add(...containerClasses);
380
+ this._container.insertBefore(
381
+ this._notificationsContainer,
382
+ notificationsFirst ? this._menuElement : null
383
+ );
384
+ }
385
+ _setNotificationsCount(count) {
386
+ const countElement = this._notificationCountElement;
387
+ if (countElement && count > 0) {
388
+ countElement.innerHTML = createTrustedHTML(
389
+ this._win,
390
+ `<strong>${count}</strong> notification${count > 1 ? "s" : ""}`
391
+ );
392
+ this._menuElement.style.display = "block";
393
+ } else {
394
+ this._menuElement.style.display = "none";
395
+ }
396
+ }
397
+ _setShowHideButtonsVisibility() {
398
+ const showAllButton = this._showAllButton;
399
+ const hideAllButton = this._hideAllButton;
400
+ if (!showAllButton || !hideAllButton) {
401
+ return;
402
+ }
403
+ let allHidden = true;
404
+ let allVisible = true;
405
+ for (let notification of this._notifications) {
406
+ if (notification.isHidden) {
407
+ allVisible = false;
408
+ } else {
409
+ allHidden = false;
410
+ }
411
+ if (!allHidden && !allVisible) {
412
+ break;
413
+ }
414
+ }
415
+ hideAllButton.style.display = allHidden ? "none" : "block";
416
+ showAllButton.style.display = allVisible ? "none" : "block";
417
+ }
138
418
  addNotification(notification) {
139
419
  if (this._notifications.has(notification)) {
140
420
  return;
141
421
  }
422
+ if (this._isMuted) {
423
+ notification.toggle(false, true);
424
+ }
142
425
  this._notifications.add(notification);
143
- this._container.appendChild(NotificationUI.getElement(notification));
426
+ this._notificationsContainer.appendChild(
427
+ NotificationUI.getElement(notification)
428
+ );
429
+ NotificationUI.setOnToggle(notification, () => {
430
+ this._setShowHideButtonsVisibility();
431
+ });
432
+ this._setNotificationsCount(this._notifications.size);
433
+ this._setShowHideButtonsVisibility();
144
434
  }
145
435
  removeNotification(notification) {
146
436
  if (!this._notifications.has(notification)) {
147
437
  return;
148
438
  }
149
439
  this._notifications.delete(notification);
150
- this._container.removeChild(NotificationUI.getElement(notification));
440
+ this._setNotificationsCount(this._notifications.size);
441
+ this._setShowHideButtonsVisibility();
442
+ }
443
+ hideAll() {
444
+ this._notifications.forEach((notification) => {
445
+ notification.toggle(false);
446
+ });
447
+ this._setShowHideButtonsVisibility();
448
+ }
449
+ showAll() {
450
+ this._notifications.forEach((notification) => {
451
+ notification.toggle(true);
452
+ });
453
+ this._setShowHideButtonsVisibility();
151
454
  }
152
455
  };
153
456
  var ElementHighlighter = class {
@@ -370,91 +673,13 @@ function getStackTrace() {
370
673
  }
371
674
  }
372
675
 
373
- // src/rules/base.ts
374
- var ValidationRule = class {
375
- constructor() {
376
- __publicField(this, "_window");
377
- __publicField(this, "_exceptions", []);
378
- }
379
- static setWindow(instance, window2) {
380
- instance._window = window2;
381
- }
382
- static checkExceptions(instance, element) {
383
- for (const exception of instance._exceptions) {
384
- if (exception(element)) {
385
- return true;
386
- }
387
- }
388
- return false;
389
- }
390
- addException(checkException) {
391
- var _a;
392
- (_a = this._exceptions) == null ? void 0 : _a.push(checkException);
393
- }
394
- removeException(checkException) {
395
- const index = this._exceptions.indexOf(checkException);
396
- if (index >= 0) {
397
- this._exceptions.splice(index, 1);
398
- }
399
- }
400
- /**
401
- * Window is set when the rule is added to the AbleDOM instance.
402
- */
403
- get window() {
404
- return this._window;
405
- }
406
- };
407
-
408
676
  // src/core.ts
409
- var _ValidationErrorReport = class _ValidationErrorReport {
410
- constructor(element, error, onHide) {
411
- this.element = element;
412
- this.error = error;
413
- __publicField(this, "_notification");
414
- __publicField(this, "_onHide");
415
- this._onHide = onHide;
416
- this.report();
417
- }
418
- update(error) {
419
- this.error = error;
420
- this.report();
421
- }
422
- report() {
423
- if (!_ValidationErrorReport._notificationsUI) {
424
- _ValidationErrorReport._notificationsUI = new NotificationsUI(window);
425
- }
426
- let notification = this._notification;
427
- if (notification) {
428
- } else {
429
- notification = this._notification = new NotificationUI(
430
- this.element,
431
- this.error
432
- );
433
- }
434
- _ValidationErrorReport._notificationsUI.addNotification(notification);
435
- }
436
- hide() {
437
- var _a;
438
- (_a = this._onHide) == null ? void 0 : _a.call(this);
439
- }
440
- remove() {
441
- var _a;
442
- if (this._notification) {
443
- (_a = _ValidationErrorReport._notificationsUI) == null ? void 0 : _a.removeNotification(
444
- this._notification
445
- );
446
- delete this._notification;
447
- }
448
- }
449
- };
450
- __publicField(_ValidationErrorReport, "_notificationsUI");
451
- var ValidationErrorReport = _ValidationErrorReport;
452
677
  var AbleDOM = class {
453
678
  constructor(win) {
454
- __publicField(this, "_window");
679
+ __publicField(this, "_win");
455
680
  __publicField(this, "_observer");
456
681
  __publicField(this, "_clearValidationTimeout");
457
- __publicField(this, "_elementsWithErrors", /* @__PURE__ */ new Set());
682
+ __publicField(this, "_elementsWithNotifications", /* @__PURE__ */ new Set());
458
683
  __publicField(this, "_changedElementIds", /* @__PURE__ */ new Set());
459
684
  __publicField(this, "_elementsDependingOnId", /* @__PURE__ */ new Map());
460
685
  __publicField(this, "_dependantIdsByElement", /* @__PURE__ */ new Map());
@@ -469,19 +694,10 @@ var AbleDOM = class {
469
694
  return;
470
695
  }
471
696
  for (const rule of this._rules) {
472
- (_a = rule.focused) == null ? void 0 : _a.call(rule, event).then(
473
- (focusError) => {
474
- if (focusError) {
475
- this._addValidationError(
476
- focusError.element,
477
- rule,
478
- focusError.error
479
- );
480
- }
481
- },
482
- () => {
483
- }
484
- );
697
+ const focusNotification = (_a = rule.focused) == null ? void 0 : _a.call(rule, event);
698
+ if (focusNotification) {
699
+ this._addNotification(rule, focusNotification);
700
+ }
485
701
  }
486
702
  });
487
703
  __publicField(this, "_onFocusOut", (event) => {
@@ -491,22 +707,16 @@ var AbleDOM = class {
491
707
  return;
492
708
  }
493
709
  for (const rule of this._rules) {
494
- (_a = rule.blurred) == null ? void 0 : _a.call(rule, event).then(
495
- (focusError) => {
496
- if (focusError) {
497
- this._addValidationError(
498
- focusError.element,
499
- rule,
500
- focusError.error
501
- );
502
- }
503
- },
504
- () => {
505
- }
506
- );
710
+ const blurNotification = (_a = rule.blurred) == null ? void 0 : _a.call(rule, event);
711
+ if (blurNotification) {
712
+ this._addNotification(rule, blurNotification);
713
+ }
507
714
  }
508
715
  });
509
- this._window = win;
716
+ __publicField(this, "_notifyAsync", (rule, notification) => {
717
+ this._addNotification(rule, notification);
718
+ });
719
+ this._win = win;
510
720
  const _elementsToValidate = /* @__PURE__ */ new Set();
511
721
  const _elementsToRemove = /* @__PURE__ */ new Set();
512
722
  win.document.addEventListener("focusin", this._onFocusIn, true);
@@ -575,7 +785,7 @@ var AbleDOM = class {
575
785
  };
576
786
  function lookUp(node) {
577
787
  for (let n = node; n; n = n.parentNode) {
578
- addTarget(n, false);
788
+ addTarget(n, _elementsToRemove.has(node));
579
789
  }
580
790
  }
581
791
  function findTargets(node, removed) {
@@ -633,49 +843,49 @@ var AbleDOM = class {
633
843
  this._idByElement.delete(element);
634
844
  }
635
845
  }
636
- _addValidationError(element, rule, error) {
637
- if (!error) {
638
- this._removeElementError(element, rule);
846
+ _addNotification(rule, notification) {
847
+ const element = notification == null ? void 0 : notification.element;
848
+ if (!notification) {
849
+ this._removeNotification(element || this._win.document.body, rule);
639
850
  return;
640
851
  }
641
- if (rule.anchored) {
852
+ let notificationUI;
853
+ if (rule.anchored && element) {
642
854
  let abledomOnElement = element.__abledom;
643
855
  if (!abledomOnElement) {
644
856
  abledomOnElement = element.__abledom = {};
645
857
  }
646
- let errors = abledomOnElement.errors;
647
- if (!errors) {
648
- errors = abledomOnElement.errors = /* @__PURE__ */ new Map();
858
+ let notifications = abledomOnElement.notifications;
859
+ if (!notifications) {
860
+ notifications = abledomOnElement.notifications = /* @__PURE__ */ new Map();
649
861
  }
650
- const report = errors.get(rule);
651
- if (report) {
652
- report.update(error);
653
- } else {
654
- errors.set(rule, new ValidationErrorReport(element, error));
862
+ notificationUI = notifications.get(rule);
863
+ if (!notificationUI) {
864
+ notificationUI = new NotificationUI(this._win, rule);
865
+ notifications.set(rule, notificationUI);
655
866
  }
656
- this._elementsWithErrors.add(element);
867
+ this._elementsWithNotifications.add(element);
657
868
  } else {
658
- const report = new ValidationErrorReport(element, error, () => {
659
- report.remove();
660
- });
869
+ notificationUI = new NotificationUI(this._win, rule);
661
870
  }
871
+ notificationUI.update(notification);
662
872
  }
663
- _removeElementError(element, rule) {
873
+ _removeNotification(element, rule) {
664
874
  var _a;
665
875
  if (!rule.anchored) {
666
876
  return;
667
877
  }
668
- const errors = (_a = element.__abledom) == null ? void 0 : _a.errors;
669
- if (!errors) {
878
+ const notifications = (_a = element.__abledom) == null ? void 0 : _a.notifications;
879
+ if (!notifications) {
670
880
  return;
671
881
  }
672
- const report = errors.get(rule);
673
- if (report) {
674
- report.remove();
675
- errors.delete(rule);
882
+ const notification = notifications.get(rule);
883
+ if (notification) {
884
+ notification.dispose();
885
+ notifications.delete(rule);
676
886
  }
677
- if (errors.size === 0) {
678
- this._elementsWithErrors.delete(element);
887
+ if (notifications.size === 0) {
888
+ this._elementsWithNotifications.delete(element);
679
889
  delete element.__abledom;
680
890
  }
681
891
  }
@@ -690,26 +900,26 @@ var AbleDOM = class {
690
900
  }
691
901
  elements.forEach((element) => {
692
902
  var _a, _b, _c, _d, _e;
693
- if (isAccessibilityAffectingElement(element) || ((_a = element.__abledom) == null ? void 0 : _a.errors)) {
903
+ if (isAccessibilityAffectingElement(element) || ((_a = element.__abledom) == null ? void 0 : _a.notifications)) {
694
904
  const dependsOnIds = /* @__PURE__ */ new Set();
695
905
  for (const rule of this._rules) {
696
- if (((_b = rule.accept) == null ? void 0 : _b.call(rule, element)) === false) {
906
+ if (!rule.validate || ((_b = rule.accept) == null ? void 0 : _b.call(rule, element)) === false) {
697
907
  continue;
698
908
  }
699
909
  if (ValidationRule.checkExceptions(rule, element)) {
700
910
  continue;
701
911
  }
702
912
  const validationResult = (_c = rule.validate) == null ? void 0 : _c.call(rule, element);
703
- if (validationResult) {
704
- this._addValidationError(element, rule, validationResult.error);
913
+ if (validationResult == null ? void 0 : validationResult.notification) {
914
+ this._addNotification(rule, validationResult.notification);
705
915
  const ids = validationResult.dependsOnIds;
706
916
  if (ids) {
707
917
  for (const id of ids) {
708
918
  dependsOnIds.add(id);
709
919
  }
710
920
  }
711
- } else if ((_e = (_d = element.__abledom) == null ? void 0 : _d.errors) == null ? void 0 : _e.has(rule)) {
712
- this._removeElementError(element, rule);
921
+ } else if ((_e = (_d = element.__abledom) == null ? void 0 : _d.notifications) == null ? void 0 : _e.has(rule)) {
922
+ this._removeNotification(element, rule);
713
923
  }
714
924
  }
715
925
  this._processElementDependingOnIds(
@@ -761,8 +971,8 @@ var AbleDOM = class {
761
971
  _remove(elements) {
762
972
  elements.forEach((element) => {
763
973
  var _a, _b;
764
- const rules = [...((_b = (_a = element.__abledom) == null ? void 0 : _a.errors) == null ? void 0 : _b.keys()) || []];
765
- rules.forEach((rule) => this._removeElementError(element, rule));
974
+ const rules = [...((_b = (_a = element.__abledom) == null ? void 0 : _a.notifications) == null ? void 0 : _b.keys()) || []];
975
+ rules.forEach((rule) => this._removeNotification(element, rule));
766
976
  });
767
977
  }
768
978
  addRule(rule) {
@@ -784,23 +994,24 @@ var AbleDOM = class {
784
994
  }
785
995
  this._isStarted = true;
786
996
  for (const rule of this._rules) {
787
- ValidationRule.setWindow(rule, this._window);
997
+ ValidationRule.init(rule, this._win, this._notifyAsync);
788
998
  (_a = rule.start) == null ? void 0 : _a.call(rule);
789
999
  }
790
1000
  (_b = this._startFunc) == null ? void 0 : _b.call(this);
791
1001
  }
792
1002
  dispose() {
793
1003
  var _a, _b;
794
- this._window.document.addEventListener("focusin", this._onFocusIn, true);
795
- this._window.document.addEventListener("focusout", this._onFocusOut, true);
796
- this._remove(this._elementsWithErrors);
797
- this._elementsWithErrors.clear();
1004
+ this._win.document.addEventListener("focusin", this._onFocusIn, true);
1005
+ this._win.document.addEventListener("focusout", this._onFocusOut, true);
1006
+ this._remove(this._elementsWithNotifications);
1007
+ this._elementsWithNotifications.clear();
798
1008
  this._dependantIdsByElement.clear();
799
1009
  this._elementsDependingOnId.clear();
800
1010
  this._idByElement.clear();
801
1011
  (_a = this._clearValidationTimeout) == null ? void 0 : _a.call(this);
802
1012
  for (const rule of this._rules) {
803
1013
  (_b = rule.stop) == null ? void 0 : _b.call(rule);
1014
+ ValidationRule.dispose(rule);
804
1015
  }
805
1016
  this._rules = [];
806
1017
  if (this._startFunc) {
@@ -815,6 +1026,7 @@ var AbleDOM = class {
815
1026
  var AtomicRule = class extends ValidationRule {
816
1027
  constructor() {
817
1028
  super(...arguments);
1029
+ __publicField(this, "type", 1 /* Error */);
818
1030
  __publicField(this, "name", "atomic");
819
1031
  __publicField(this, "anchored", true);
820
1032
  }
@@ -848,9 +1060,10 @@ var AtomicRule = class extends ValidationRule {
848
1060
  ).snapshotItem(0);
849
1061
  if (parentAtomic) {
850
1062
  return {
851
- error: {
1063
+ notification: {
852
1064
  id: "focusable-in-atomic",
853
1065
  message: "Focusable element inside atomic focusable.",
1066
+ element,
854
1067
  rel: parentAtomic
855
1068
  }
856
1069
  };
@@ -877,6 +1090,7 @@ var _keyboardEditableInputTypes = /* @__PURE__ */ new Set([
877
1090
  var FocusableElementLabelRule = class extends ValidationRule {
878
1091
  constructor() {
879
1092
  super(...arguments);
1093
+ __publicField(this, "type", 1 /* Error */);
880
1094
  __publicField(this, "name", "FocusableElementLabelRule");
881
1095
  __publicField(this, "anchored", true);
882
1096
  }
@@ -980,9 +1194,10 @@ var FocusableElementLabelRule = class extends ValidationRule {
980
1194
  }
981
1195
  }
982
1196
  return {
983
- error: isElementVisible(element) ? {
1197
+ notification: isElementVisible(element) ? {
984
1198
  id: "focusable-element-label",
985
- message: "Focusable element must have a non-empty text label."
1199
+ message: "Focusable element must have a non-empty text label.",
1200
+ element
986
1201
  } : void 0,
987
1202
  dependsOnIds: new Set(labelledByValues)
988
1203
  };
@@ -993,6 +1208,7 @@ var FocusableElementLabelRule = class extends ValidationRule {
993
1208
  var ExistingIdRule = class extends ValidationRule {
994
1209
  constructor() {
995
1210
  super(...arguments);
1211
+ __publicField(this, "type", 1 /* Error */);
996
1212
  __publicField(this, "name", "existing-id");
997
1213
  __publicField(this, "anchored", true);
998
1214
  }
@@ -1017,9 +1233,10 @@ var ExistingIdRule = class extends ValidationRule {
1017
1233
  }
1018
1234
  }
1019
1235
  return {
1020
- error: {
1236
+ notification: {
1021
1237
  id: "missing-id",
1022
- message: `Elements with referenced ids do not extist.`
1238
+ message: `Elements with referenced ids do not extist.`,
1239
+ element
1023
1240
  },
1024
1241
  dependsOnIds: new Set(ids)
1025
1242
  };
@@ -1030,6 +1247,7 @@ var ExistingIdRule = class extends ValidationRule {
1030
1247
  var FocusLostRule = class extends ValidationRule {
1031
1248
  constructor() {
1032
1249
  super(...arguments);
1250
+ __publicField(this, "type", 1 /* Error */);
1033
1251
  __publicField(this, "name", "focus-lost");
1034
1252
  __publicField(this, "anchored", false);
1035
1253
  __publicField(this, "_focusLostTimeout", 2e3);
@@ -1039,6 +1257,8 @@ var FocusLostRule = class extends ValidationRule {
1039
1257
  __publicField(this, "_focusedElementPosition");
1040
1258
  __publicField(this, "_lastFocusStack");
1041
1259
  __publicField(this, "_lastBlurStack");
1260
+ __publicField(this, "_mouseEventTimer");
1261
+ __publicField(this, "_releaseMouseEvent");
1042
1262
  }
1043
1263
  _serializeElementPosition(element) {
1044
1264
  const position = [];
@@ -1052,7 +1272,7 @@ var FocusLostRule = class extends ValidationRule {
1052
1272
  }
1053
1273
  return position;
1054
1274
  }
1055
- async focused(event) {
1275
+ focused(event) {
1056
1276
  var _a;
1057
1277
  const target = event.target;
1058
1278
  (_a = this._clearScheduledFocusLost) == null ? void 0 : _a.call(this);
@@ -1063,53 +1283,71 @@ var FocusLostRule = class extends ValidationRule {
1063
1283
  }
1064
1284
  return null;
1065
1285
  }
1066
- async blurred(event) {
1286
+ blurred(event) {
1067
1287
  var _a;
1068
1288
  const target = event.target;
1069
1289
  const win = this.window;
1070
1290
  (_a = this._clearScheduledFocusLost) == null ? void 0 : _a.call(this);
1071
- if (!target || !win || event.relatedTarget) {
1291
+ if (!target || !win || event.relatedTarget || this._mouseEventTimer) {
1072
1292
  return null;
1073
1293
  }
1074
- let focusLostTimer;
1075
- let rejectPromise;
1076
1294
  const targetPosition = this._focusedElement === target ? this._focusedElementPosition : void 0;
1077
1295
  this._lastBlurStack = getStackTrace();
1078
1296
  this._focusedElement = void 0;
1079
1297
  this._focusedElementPosition = void 0;
1298
+ const focusLostTimer = win.setTimeout(() => {
1299
+ delete this._clearScheduledFocusLost;
1300
+ if (win.document.body && (!win.document.activeElement || win.document.activeElement === win.document.body) && (!win.document.body.contains(target) || !isElementVisible(target))) {
1301
+ this.notify({
1302
+ element: target,
1303
+ id: "focus-lost",
1304
+ message: "Focus lost.",
1305
+ stack: this._lastBlurStack,
1306
+ relStack: this._lastFocusStack,
1307
+ position: targetPosition || []
1308
+ });
1309
+ }
1310
+ }, this._focusLostTimeout);
1080
1311
  this._clearScheduledFocusLost = () => {
1081
1312
  delete this._clearScheduledFocusLost;
1082
- rejectPromise == null ? void 0 : rejectPromise();
1083
- if (focusLostTimer) {
1084
- win.clearTimeout(focusLostTimer);
1085
- focusLostTimer = void 0;
1313
+ win.clearTimeout(focusLostTimer);
1314
+ };
1315
+ return null;
1316
+ }
1317
+ start() {
1318
+ const win = this.window;
1319
+ if (!win) {
1320
+ return;
1321
+ }
1322
+ const onMouseEvent = () => {
1323
+ if (!this._mouseEventTimer) {
1324
+ this._mouseEventTimer = win.setTimeout(() => {
1325
+ this._mouseEventTimer = void 0;
1326
+ }, 0);
1086
1327
  }
1087
1328
  };
1088
- return new Promise((resolve, reject) => {
1089
- rejectPromise = () => {
1090
- rejectPromise = void 0;
1091
- reject();
1092
- };
1093
- focusLostTimer = win.setTimeout(() => {
1094
- focusLostTimer = void 0;
1095
- rejectPromise = void 0;
1096
- delete this._clearScheduledFocusLost;
1097
- if (win.document.body && (!win.document.activeElement || win.document.activeElement === win.document.body) && (!win.document.body.contains(target) || !isElementVisible(target))) {
1098
- resolve({
1099
- element: target,
1100
- position: targetPosition || [],
1101
- error: {
1102
- id: "focus-lost",
1103
- message: "Focus lost.",
1104
- stack: this._lastBlurStack,
1105
- relStack: this._lastFocusStack
1106
- }
1107
- });
1108
- } else {
1109
- resolve(null);
1110
- }
1111
- }, this._focusLostTimeout);
1112
- });
1329
+ win.addEventListener("mousedown", onMouseEvent, true);
1330
+ win.addEventListener("mouseup", onMouseEvent, true);
1331
+ win.addEventListener("mousemove", onMouseEvent, true);
1332
+ this._releaseMouseEvent = () => {
1333
+ delete this._releaseMouseEvent;
1334
+ if (this._mouseEventTimer) {
1335
+ win.clearTimeout(this._mouseEventTimer);
1336
+ delete this._mouseEventTimer;
1337
+ }
1338
+ win.removeEventListener("mousedown", onMouseEvent, true);
1339
+ win.removeEventListener("mouseup", onMouseEvent, true);
1340
+ win.removeEventListener("mousemove", onMouseEvent, true);
1341
+ };
1342
+ }
1343
+ stop() {
1344
+ var _a, _b;
1345
+ (_a = this._releaseMouseEvent) == null ? void 0 : _a.call(this);
1346
+ (_b = this._clearScheduledFocusLost) == null ? void 0 : _b.call(this);
1347
+ this._focusedElement = void 0;
1348
+ this._focusedElementPosition = void 0;
1349
+ this._lastFocusStack = void 0;
1350
+ this._lastBlurStack = void 0;
1113
1351
  }
1114
1352
  };
1115
1353
 
@@ -1117,53 +1355,96 @@ var FocusLostRule = class extends ValidationRule {
1117
1355
  var BadFocusRule = class extends ValidationRule {
1118
1356
  constructor() {
1119
1357
  super(...arguments);
1358
+ __publicField(this, "type", 1 /* Error */);
1120
1359
  __publicField(this, "name", "bad-focus");
1121
1360
  __publicField(this, "anchored", false);
1122
1361
  __publicField(this, "_lastFocusStack");
1123
1362
  __publicField(this, "_lastBlurStack");
1124
- __publicField(this, "_reject");
1363
+ __publicField(this, "_clearCheckTimer");
1125
1364
  }
1126
- async focused() {
1127
- var _a;
1365
+ focused() {
1128
1366
  this._lastFocusStack = getStackTrace();
1129
- (_a = this._reject) == null ? void 0 : _a.call(this);
1130
1367
  return null;
1131
1368
  }
1132
- async blurred() {
1369
+ blurred() {
1133
1370
  var _a;
1134
- (_a = this._reject) == null ? void 0 : _a.call(this);
1135
1371
  const win = this.window;
1136
1372
  if (!win) {
1137
1373
  return null;
1138
1374
  }
1139
1375
  this._lastBlurStack = getStackTrace();
1140
- return new Promise((resolve, reject) => {
1141
- let checkTimer;
1142
- this._reject = () => {
1143
- if (checkTimer) {
1144
- win.clearTimeout(checkTimer);
1145
- checkTimer = void 0;
1146
- }
1147
- this._reject = void 0;
1148
- reject();
1149
- };
1150
- checkTimer = win.setTimeout(() => {
1151
- checkTimer = void 0;
1152
- this._reject = void 0;
1153
- if (document.activeElement && !isElementVisible(document.activeElement)) {
1154
- resolve({
1155
- element: document.activeElement,
1156
- error: {
1157
- id: "bad-focus",
1158
- message: "Focused stolen by invisible element.",
1159
- stack: this._lastBlurStack,
1160
- relStack: this._lastFocusStack
1161
- }
1162
- });
1163
- } else {
1164
- resolve(null);
1165
- }
1166
- }, 100);
1376
+ (_a = this._clearCheckTimer) == null ? void 0 : _a.call(this);
1377
+ const checkTimer = win.setTimeout(() => {
1378
+ delete this._clearCheckTimer;
1379
+ if (document.activeElement && !isElementVisible(document.activeElement)) {
1380
+ this.notify({
1381
+ id: "bad-focus",
1382
+ message: "Focused stolen by invisible element.",
1383
+ element: document.activeElement,
1384
+ stack: this._lastBlurStack,
1385
+ relStack: this._lastFocusStack
1386
+ });
1387
+ }
1388
+ }, 100);
1389
+ this._clearCheckTimer = () => {
1390
+ delete this._clearCheckTimer;
1391
+ win.clearTimeout(checkTimer);
1392
+ };
1393
+ return null;
1394
+ }
1395
+ stop() {
1396
+ var _a;
1397
+ (_a = this._clearCheckTimer) == null ? void 0 : _a.call(this);
1398
+ this._clearCheckTimer = void 0;
1399
+ this._lastFocusStack = void 0;
1400
+ this._lastBlurStack = void 0;
1401
+ }
1402
+ };
1403
+
1404
+ // src/rules/find.ts
1405
+ var FindElementRule = class extends ValidationRule {
1406
+ constructor() {
1407
+ super(...arguments);
1408
+ __publicField(this, "type", 2 /* Warning */);
1409
+ __publicField(this, "name", "find-element");
1410
+ __publicField(this, "anchored", true);
1411
+ __publicField(this, "_conditions", {});
1412
+ }
1413
+ addCondition(name, condition) {
1414
+ this._conditions[name] = condition;
1415
+ }
1416
+ removeCondition(name) {
1417
+ delete this._conditions[name];
1418
+ }
1419
+ validate(element) {
1420
+ for (const name of Object.keys(this._conditions)) {
1421
+ if (this._conditions[name](element)) {
1422
+ return {
1423
+ notification: {
1424
+ id: "find-element",
1425
+ message: `Element found: ${name}.`,
1426
+ element
1427
+ }
1428
+ };
1429
+ }
1430
+ }
1431
+ return null;
1432
+ }
1433
+ };
1434
+
1435
+ // src/rules/notify.ts
1436
+ var CustomNotifyRule = class extends ValidationRule {
1437
+ constructor() {
1438
+ super(...arguments);
1439
+ __publicField(this, "type", 3 /* Info */);
1440
+ __publicField(this, "name", "custom-notify");
1441
+ __publicField(this, "anchored", false);
1442
+ }
1443
+ customNotify(message, element) {
1444
+ this.notify({
1445
+ id: "custom-notify",
1446
+ message,
1447
+ element
1167
1448
  });
1168
1449
  }
1169
1450
  };
@@ -1172,10 +1453,18 @@ var BadFocusRule = class extends ValidationRule {
1172
1453
  AbleDOM,
1173
1454
  AtomicRule,
1174
1455
  BadFocusRule,
1456
+ CustomNotifyRule,
1175
1457
  ExistingIdRule,
1458
+ FindElementRule,
1176
1459
  FocusLostRule,
1177
1460
  FocusableElementLabelRule,
1178
- ValidationRule
1461
+ ValidationRule,
1462
+ ValidationRuleType,
1463
+ hasAccessibilityAttribute,
1464
+ isAccessibilityAffectingElement,
1465
+ isDisplayNone,
1466
+ isElementVisible,
1467
+ matchesSelector
1179
1468
  });
1180
1469
  /*!
1181
1470
  * Copyright (c) Microsoft Corporation. All rights reserved.