abledom 0.0.0 → 0.0.2

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.
@@ -0,0 +1,1416 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
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
+
60
+ // inline-file:/Users/marata/Documents/Work/abledom/src/ui/ui.css
61
+ var ui_default = "#abledom-report {\n bottom: 20px;\n display: flex;\n flex-direction: column;\n left: 10px;\n max-height: 80%;\n max-width: 60%;\n padding: 4px 8px;\n position: 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";
62
+
63
+ // inline-file:/Users/marata/Documents/Work/abledom/src/ui/close.svg
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';
65
+
66
+ // inline-file:/Users/marata/Documents/Work/abledom/src/ui/help.svg
67
+ var help_default = '<svg width="20" height="20" viewBox="0 0 24 24" fill="none"\n stroke="currentColor" stroke-width="2" stroke-linecap="round"\n stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg">\n <circle cx="12" cy="12" r="10"/>\n <path d="M9.09 9a3 3 0 1 1 5.83 1c-.28 1.02-1.22 1.5-2.01 2.1-.76.58-1 1.1-1 2"/>\n <circle cx="12" cy="17" r="0.5"/>\n</svg>';
68
+
69
+ // inline-file:/Users/marata/Documents/Work/abledom/src/ui/log.svg
70
+ var log_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 <polyline points="4 7 9 12 4 17"/>\n <line x1="11" y1="19" x2="20" y2="19"/>\n</svg>';
71
+
72
+ // inline-file:/Users/marata/Documents/Work/abledom/src/ui/reveal.svg
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>';
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
+
96
+ // src/ui/ui.ts
97
+ var pressedClass = "pressed";
98
+ var _NotificationUI = class _NotificationUI {
99
+ constructor(win, rule) {
100
+ __publicField(this, "_win");
101
+ __publicField(this, "_wrapper");
102
+ __publicField(this, "_rule");
103
+ __publicField(this, "_onToggle");
104
+ __publicField(this, "isHidden", false);
105
+ this._win = win;
106
+ this._rule = rule;
107
+ if (!_NotificationUI._notificationsUI) {
108
+ _NotificationUI._notificationsUI = new NotificationsUI(this._win);
109
+ }
110
+ this._wrapper = win.document.createElement(
111
+ "div"
112
+ );
113
+ if (!_NotificationUI._highlight) {
114
+ _NotificationUI._highlight = new ElementHighlighter(win);
115
+ }
116
+ _NotificationUI._notificationsUI.addNotification(this);
117
+ }
118
+ static setOnToggle(instance, onToggle) {
119
+ instance._onToggle = onToggle;
120
+ }
121
+ static getElement(instance) {
122
+ return instance._wrapper;
123
+ }
124
+ update(notification) {
125
+ var _a;
126
+ const win = this._win;
127
+ const rule = this._rule;
128
+ const wrapper = this._wrapper;
129
+ const element = notification.element;
130
+ wrapper.__abledomui = true;
131
+ wrapper.innerHTML = `
132
+ <div class="abledom-notification-container"><div class="abledom-notification${rule.type === 2 /* Warning */ ? " abledom-notification_warning" : rule.type === 3 /* Info */ ? " abledom-notification_info" : ""}">
133
+ <button class="button" title="Log to Console">${log_default}</button>
134
+ <button class="button" title="Reveal in Elements panel">${reveal_default}</button>
135
+ ${notification.message}
136
+ <a href class="button close" href="/" title="Open help" target="_blank">${help_default}</a>
137
+ <button class="button close" class="close" title="Hide">${close_default}</button>
138
+ </div></div>`;
139
+ const container = wrapper.firstElementChild;
140
+ const buttons = wrapper.querySelectorAll("button");
141
+ const logButton = buttons[0];
142
+ const revealButton = buttons[1];
143
+ const closeButton = buttons[2];
144
+ logButton.onclick = () => {
145
+ console.error(
146
+ "AbleDOM: ",
147
+ "\nmessage:",
148
+ notification.message,
149
+ "\nelement:",
150
+ element,
151
+ ...notification.rel ? ["\nrelative:", notification.rel] : [],
152
+ "\nnotification:",
153
+ notification
154
+ );
155
+ };
156
+ const hasDevTools = !!((_a = win.__ableDOMDevtools) == null ? void 0 : _a.revealElement) && false;
157
+ if (hasDevTools && element && win.document.body.contains(element)) {
158
+ revealButton.onclick = () => {
159
+ var _a2;
160
+ const revealElement = (_a2 = win.__ableDOMDevtools) == null ? void 0 : _a2.revealElement;
161
+ if (revealElement && win.document.body.contains(element)) {
162
+ revealElement(element).then((revealed) => {
163
+ if (!revealed) {
164
+ }
165
+ });
166
+ }
167
+ };
168
+ } else {
169
+ revealButton.style.display = "none";
170
+ }
171
+ closeButton.onclick = () => {
172
+ var _a2;
173
+ this.toggle(false);
174
+ (_a2 = _NotificationUI._highlight) == null ? void 0 : _a2.hide();
175
+ };
176
+ container.onmouseover = () => {
177
+ var _a2;
178
+ element && ((_a2 = _NotificationUI._highlight) == null ? void 0 : _a2.highlight(element));
179
+ };
180
+ container.onmouseout = () => {
181
+ var _a2;
182
+ (_a2 = _NotificationUI._highlight) == null ? void 0 : _a2.hide();
183
+ };
184
+ }
185
+ toggle(show, initial = false) {
186
+ var _a;
187
+ this.isHidden = !show;
188
+ if (!initial) {
189
+ (_a = this._onToggle) == null ? void 0 : _a.call(this, this, show);
190
+ if (!this._rule.anchored && !show) {
191
+ this.dispose();
192
+ }
193
+ }
194
+ this._wrapper.style.display = show ? "block" : "none";
195
+ }
196
+ dispose() {
197
+ var _a;
198
+ this._wrapper.remove();
199
+ (_a = _NotificationUI._notificationsUI) == null ? void 0 : _a.removeNotification(this);
200
+ }
201
+ };
202
+ __publicField(_NotificationUI, "_notificationsUI");
203
+ __publicField(_NotificationUI, "_highlight");
204
+ var NotificationUI = _NotificationUI;
205
+ var NotificationsUI = class {
206
+ constructor(win) {
207
+ __publicField(this, "_container");
208
+ __publicField(this, "_notificationsContainer");
209
+ __publicField(this, "_menuElement");
210
+ __publicField(this, "_notificationCountElement");
211
+ __publicField(this, "_showAllButton");
212
+ __publicField(this, "_hideAllButton");
213
+ __publicField(this, "_alignBottomLeftButton");
214
+ __publicField(this, "_alignTopLeftButton");
215
+ __publicField(this, "_alignTopRightButton");
216
+ __publicField(this, "_alignBottomRightButton");
217
+ __publicField(this, "_isMuted", false);
218
+ __publicField(this, "_notifications", /* @__PURE__ */ new Set());
219
+ var _a;
220
+ const container = this._container = win.document.createElement("div");
221
+ container.__abledomui = true;
222
+ container.id = "abledom-report";
223
+ container.innerHTML = `<style>${ui_default}</style>`;
224
+ const notificationsContainer = this._notificationsContainer = win.document.createElement("div");
225
+ notificationsContainer.className = "abledom-notifications-container";
226
+ container.appendChild(notificationsContainer);
227
+ const menuElement = this._menuElement = win.document.createElement("div");
228
+ menuElement.className = "abledom-menu-container";
229
+ menuElement.innerHTML = `<div class="abledom-menu"><span class="notifications-count"></span
230
+ ><button class="button" title="Show all notifications">${showall_default}</button
231
+ ><button class="button" title="Hide all notifications">${hideall_default}</button
232
+ ><button class="button" title="Mute newly appearing notifications">${muteall_default}</button
233
+ ><button class="button align-button align-button-first pressed" title="Attach notifications to bottom left">${alignbottomleft_default}</button
234
+ ><button class="button align-button" title="Attach notifications to top left">${aligntopleft_default}</button
235
+ ><button class="button align-button" title="Attach notifications to top right">${aligntopright_default}</button
236
+ ><button class="button align-button align-button-last" title="Attach notifications to bottom right">${alignbottomright_default}</button
237
+ ></div>`;
238
+ const [
239
+ notificationCountElement,
240
+ showAllButton,
241
+ hideAllButton,
242
+ muteButton,
243
+ alignBottomLeftButton,
244
+ alignTopLeftButton,
245
+ alignTopRightButton,
246
+ alignBottomRightButton
247
+ ] = ((_a = menuElement.firstElementChild) == null ? void 0 : _a.childNodes) || [];
248
+ 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) {
249
+ container.appendChild(menuElement);
250
+ this._notificationCountElement = notificationCountElement;
251
+ this._showAllButton = showAllButton;
252
+ this._hideAllButton = hideAllButton;
253
+ this._alignBottomLeftButton = alignBottomLeftButton;
254
+ this._alignTopLeftButton = alignTopLeftButton;
255
+ this._alignTopRightButton = alignTopRightButton;
256
+ this._alignBottomRightButton = alignBottomRightButton;
257
+ showAllButton.onclick = () => {
258
+ this.showAll();
259
+ };
260
+ hideAllButton.onclick = () => {
261
+ this.hideAll();
262
+ };
263
+ muteButton.onclick = () => {
264
+ const isMuted = this._isMuted = muteButton.classList.toggle(pressedClass);
265
+ if (isMuted) {
266
+ muteButton.setAttribute(
267
+ "title",
268
+ "Unmute newly appearing notifications"
269
+ );
270
+ } else {
271
+ muteButton.setAttribute(
272
+ "title",
273
+ "Mute newly appearing notifications"
274
+ );
275
+ }
276
+ };
277
+ alignBottomLeftButton.onclick = () => {
278
+ this.setUIAlignment("bottom-left" /* BottomLeft */);
279
+ };
280
+ alignBottomRightButton.onclick = () => {
281
+ this.setUIAlignment("bottom-right" /* BottomRight */);
282
+ };
283
+ alignTopLeftButton.onclick = () => {
284
+ this.setUIAlignment("top-left" /* TopLeft */);
285
+ };
286
+ alignTopRightButton.onclick = () => {
287
+ this.setUIAlignment("top-right" /* TopRight */);
288
+ };
289
+ }
290
+ win.document.body.appendChild(container);
291
+ }
292
+ setUIAlignment(alignment) {
293
+ var _a, _b, _c, _d, _e, _f, _g, _h;
294
+ (_a = this._alignBottomLeftButton) == null ? void 0 : _a.classList.remove(pressedClass);
295
+ (_b = this._alignBottomRightButton) == null ? void 0 : _b.classList.remove(pressedClass);
296
+ (_c = this._alignTopLeftButton) == null ? void 0 : _c.classList.remove(pressedClass);
297
+ (_d = this._alignTopRightButton) == null ? void 0 : _d.classList.remove(pressedClass);
298
+ this._container.classList.remove(
299
+ "abledom-align-left",
300
+ "abledom-align-right",
301
+ "abledom-align-top",
302
+ "abledom-align-bottom"
303
+ );
304
+ let containerClasses = [];
305
+ let notificationsFirst = false;
306
+ switch (alignment) {
307
+ case "bottom-left" /* BottomLeft */:
308
+ containerClasses = ["abledom-align-left", "abledom-align-bottom"];
309
+ notificationsFirst = true;
310
+ (_e = this._alignBottomLeftButton) == null ? void 0 : _e.classList.add(pressedClass);
311
+ break;
312
+ case "bottom-right" /* BottomRight */:
313
+ containerClasses = ["abledom-align-right", "abledom-align-bottom"];
314
+ notificationsFirst = true;
315
+ (_f = this._alignBottomRightButton) == null ? void 0 : _f.classList.add(pressedClass);
316
+ break;
317
+ case "top-left" /* TopLeft */:
318
+ containerClasses = ["abledom-align-left", "abledom-align-top"];
319
+ (_g = this._alignTopLeftButton) == null ? void 0 : _g.classList.add(pressedClass);
320
+ break;
321
+ case "top-right" /* TopRight */:
322
+ containerClasses = ["abledom-align-right", "abledom-align-top"];
323
+ (_h = this._alignTopRightButton) == null ? void 0 : _h.classList.add(pressedClass);
324
+ break;
325
+ }
326
+ this._container.classList.add(...containerClasses);
327
+ this._container.insertBefore(
328
+ this._notificationsContainer,
329
+ notificationsFirst ? this._menuElement : null
330
+ );
331
+ }
332
+ _setNotificationsCount(count) {
333
+ const countElement = this._notificationCountElement;
334
+ if (countElement && count > 0) {
335
+ countElement.innerHTML = `<strong>${count}</strong> notification${count > 1 ? "s" : ""}`;
336
+ this._menuElement.style.display = "block";
337
+ } else {
338
+ this._menuElement.style.display = "none";
339
+ }
340
+ }
341
+ _setShowHideButtonsVisibility() {
342
+ const showAllButton = this._showAllButton;
343
+ const hideAllButton = this._hideAllButton;
344
+ if (!showAllButton || !hideAllButton) {
345
+ return;
346
+ }
347
+ let allHidden = true;
348
+ let allVisible = true;
349
+ for (let notification of this._notifications) {
350
+ if (notification.isHidden) {
351
+ allVisible = false;
352
+ } else {
353
+ allHidden = false;
354
+ }
355
+ if (!allHidden && !allVisible) {
356
+ break;
357
+ }
358
+ }
359
+ hideAllButton.style.display = allHidden ? "none" : "block";
360
+ showAllButton.style.display = allVisible ? "none" : "block";
361
+ }
362
+ addNotification(notification) {
363
+ if (this._notifications.has(notification)) {
364
+ return;
365
+ }
366
+ if (this._isMuted) {
367
+ notification.toggle(false, true);
368
+ }
369
+ this._notifications.add(notification);
370
+ this._notificationsContainer.appendChild(
371
+ NotificationUI.getElement(notification)
372
+ );
373
+ NotificationUI.setOnToggle(notification, () => {
374
+ this._setShowHideButtonsVisibility();
375
+ });
376
+ this._setNotificationsCount(this._notifications.size);
377
+ this._setShowHideButtonsVisibility();
378
+ }
379
+ removeNotification(notification) {
380
+ if (!this._notifications.has(notification)) {
381
+ return;
382
+ }
383
+ this._notifications.delete(notification);
384
+ this._setNotificationsCount(this._notifications.size);
385
+ this._setShowHideButtonsVisibility();
386
+ }
387
+ hideAll() {
388
+ this._notifications.forEach((notification) => {
389
+ notification.toggle(false);
390
+ });
391
+ this._setShowHideButtonsVisibility();
392
+ }
393
+ showAll() {
394
+ this._notifications.forEach((notification) => {
395
+ notification.toggle(true);
396
+ });
397
+ this._setShowHideButtonsVisibility();
398
+ }
399
+ };
400
+ var ElementHighlighter = class {
401
+ constructor(win) {
402
+ __publicField(this, "_window");
403
+ __publicField(this, "_container");
404
+ this._window = win;
405
+ const container = this._container = win.document.createElement("div");
406
+ container.__abledomui = true;
407
+ container.className = "abledom-highlight";
408
+ }
409
+ highlight(element) {
410
+ const rect = element.getBoundingClientRect();
411
+ if (rect.width === 0 || rect.height === 0) {
412
+ return;
413
+ }
414
+ const win = this._window;
415
+ const container = this._container;
416
+ const style = container.style;
417
+ if (container.parentElement !== win.document.body) {
418
+ win.document.body.appendChild(container);
419
+ }
420
+ style.width = `${rect.width}px`;
421
+ style.height = `${rect.height}px`;
422
+ style.top = `${rect.top}px`;
423
+ style.left = `${rect.left}px`;
424
+ container.style.display = "block";
425
+ }
426
+ hide() {
427
+ this._container.style.display = "none";
428
+ }
429
+ };
430
+ function isAbleDOMUIElement(element) {
431
+ for (let el = element; el; el = el.parentElement) {
432
+ if (el.__abledomui) {
433
+ return true;
434
+ }
435
+ }
436
+ return false;
437
+ }
438
+
439
+ // src/utils.ts
440
+ var focusableElementSelector = [
441
+ "a[href]",
442
+ "button:not([disabled])",
443
+ "input:not([disabled])",
444
+ "select:not([disabled])",
445
+ "textarea:not([disabled])",
446
+ "*[tabindex]",
447
+ "*[contenteditable]",
448
+ "details > summary",
449
+ "audio[controls]",
450
+ "video[controls]"
451
+ ].join(", ");
452
+ var AccessibilityAffectingElements = {
453
+ a: true,
454
+ area: true,
455
+ article: true,
456
+ aside: true,
457
+ body: true,
458
+ button: true,
459
+ datalist: true,
460
+ details: true,
461
+ dialog: true,
462
+ dl: true,
463
+ form: true,
464
+ h1: true,
465
+ h2: true,
466
+ h3: true,
467
+ h4: true,
468
+ h5: true,
469
+ h6: true,
470
+ hr: true,
471
+ iframe: true,
472
+ img: true,
473
+ input: true,
474
+ li: true,
475
+ link: true,
476
+ main: true,
477
+ menu: true,
478
+ menuitem: true,
479
+ meter: true,
480
+ nav: true,
481
+ object: true,
482
+ ol: true,
483
+ option: true,
484
+ progress: true,
485
+ section: true,
486
+ select: true,
487
+ tbody: true,
488
+ textarea: true,
489
+ tfoot: true,
490
+ th: true,
491
+ thead: true,
492
+ ul: true
493
+ };
494
+ var AccessibilityAttributes = {
495
+ role: true,
496
+ tabindex: true,
497
+ disabled: true,
498
+ required: true,
499
+ readonly: true,
500
+ hidden: true,
501
+ "aria-activedescendant": true,
502
+ "aria-atomic": true,
503
+ "aria-autocomplete": true,
504
+ "aria-busy": true,
505
+ "aria-checked": true,
506
+ "aria-colcount": true,
507
+ "aria-colindex": true,
508
+ "aria-colspan": true,
509
+ "aria-controls": true,
510
+ "aria-current": true,
511
+ "aria-describedby": true,
512
+ "aria-details": true,
513
+ "aria-disabled": true,
514
+ "aria-dropeffect": true,
515
+ "aria-errormessage": true,
516
+ "aria-expanded": true,
517
+ "aria-flowto": true,
518
+ "aria-grabbed": true,
519
+ "aria-haspopup": true,
520
+ "aria-hidden": true,
521
+ "aria-invalid": true,
522
+ "aria-keyshortcuts": true,
523
+ "aria-label": true,
524
+ "aria-labelledby": true,
525
+ "aria-level": true,
526
+ "aria-live": true,
527
+ "aria-modal": true,
528
+ "aria-multiline": true,
529
+ "aria-multiselectable": true,
530
+ "aria-orientation": true,
531
+ "aria-owns": true,
532
+ "aria-placeholder": true,
533
+ "aria-posinset": true,
534
+ "aria-pressed": true,
535
+ "aria-readonly": true,
536
+ "aria-relevant": true,
537
+ "aria-required": true,
538
+ "aria-roledescription": true,
539
+ "aria-rowcount": true,
540
+ "aria-rowindex": true,
541
+ "aria-rowspan": true,
542
+ "aria-selected": true,
543
+ "aria-setsize": true,
544
+ "aria-sort": true,
545
+ "aria-valuemax": true,
546
+ "aria-valuemin": true,
547
+ "aria-valuenow": true,
548
+ "aria-valuetext": true
549
+ };
550
+ function isAccessibilityAffectingElement(element) {
551
+ const tagName = element.tagName.toLowerCase();
552
+ const attributes = getAttributes(element);
553
+ return tagName in AccessibilityAffectingElements || hasAccessibilityAttribute(attributes);
554
+ }
555
+ function hasAccessibilityAttribute(attributes) {
556
+ for (let attrName of Object.keys(attributes)) {
557
+ if (attrName in AccessibilityAttributes && !(attrName === "role" && (attributes[attrName] === "none" || attributes[attrName] === "presentation"))) {
558
+ return true;
559
+ }
560
+ }
561
+ return false;
562
+ }
563
+ function getAttributes(element) {
564
+ const names = element.getAttributeNames();
565
+ const attributes = {};
566
+ for (let name of names) {
567
+ attributes[name] = element.getAttribute(name) || "";
568
+ }
569
+ return attributes;
570
+ }
571
+ function matchesSelector(element, selector) {
572
+ const matches = element.matches || element.matchesSelector || element.msMatchesSelector || element.webkitMatchesSelector;
573
+ return matches && matches.call(element, selector);
574
+ }
575
+ function isDisplayNone(element) {
576
+ var _a, _b;
577
+ const elementDocument = element.ownerDocument;
578
+ const computedStyle = (_a = elementDocument.defaultView) == null ? void 0 : _a.getComputedStyle(element);
579
+ if (element.offsetParent === null && elementDocument.body !== element && (computedStyle == null ? void 0 : computedStyle.position) !== "fixed") {
580
+ return true;
581
+ }
582
+ if ((computedStyle == null ? void 0 : computedStyle.visibility) === "hidden") {
583
+ return true;
584
+ }
585
+ if ((computedStyle == null ? void 0 : computedStyle.position) === "fixed") {
586
+ if (computedStyle.display === "none") {
587
+ return true;
588
+ }
589
+ if (((_b = element.parentElement) == null ? void 0 : _b.offsetParent) === null && elementDocument.body !== element.parentElement) {
590
+ return true;
591
+ }
592
+ }
593
+ return false;
594
+ }
595
+ function isElementVisible(element) {
596
+ if (!element.ownerDocument || element.nodeType !== Node.ELEMENT_NODE) {
597
+ return false;
598
+ }
599
+ if (isDisplayNone(element)) {
600
+ return false;
601
+ }
602
+ const rect = element.ownerDocument.body.getBoundingClientRect();
603
+ if (rect.width === 0 && rect.height === 0) {
604
+ return false;
605
+ }
606
+ return true;
607
+ }
608
+ function getStackTrace() {
609
+ var _a;
610
+ const oldStackTraceLimit = Error.stackTraceLimit;
611
+ try {
612
+ Error.stackTraceLimit = 1e3;
613
+ throw new Error();
614
+ } catch (e) {
615
+ Error.stackTraceLimit = oldStackTraceLimit;
616
+ return ((_a = e.stack) == null ? void 0 : _a.split("\n").slice(1).map((line) => line.trim()).filter((line) => line.startsWith("at "))) || [];
617
+ }
618
+ }
619
+
620
+ // src/core.ts
621
+ var AbleDOM = class {
622
+ constructor(win) {
623
+ __publicField(this, "_win");
624
+ __publicField(this, "_observer");
625
+ __publicField(this, "_clearValidationTimeout");
626
+ __publicField(this, "_elementsWithNotifications", /* @__PURE__ */ new Set());
627
+ __publicField(this, "_changedElementIds", /* @__PURE__ */ new Set());
628
+ __publicField(this, "_elementsDependingOnId", /* @__PURE__ */ new Map());
629
+ __publicField(this, "_dependantIdsByElement", /* @__PURE__ */ new Map());
630
+ __publicField(this, "_idByElement", /* @__PURE__ */ new Map());
631
+ __publicField(this, "_rules", []);
632
+ __publicField(this, "_startFunc");
633
+ __publicField(this, "_isStarted", false);
634
+ __publicField(this, "_onFocusIn", (event) => {
635
+ var _a;
636
+ const target = event.target;
637
+ if (target && isAbleDOMUIElement(target)) {
638
+ return;
639
+ }
640
+ for (const rule of this._rules) {
641
+ const focusNotification = (_a = rule.focused) == null ? void 0 : _a.call(rule, event);
642
+ if (focusNotification) {
643
+ this._addNotification(rule, focusNotification);
644
+ }
645
+ }
646
+ });
647
+ __publicField(this, "_onFocusOut", (event) => {
648
+ var _a;
649
+ const target = event.target;
650
+ if (target && isAbleDOMUIElement(target)) {
651
+ return;
652
+ }
653
+ for (const rule of this._rules) {
654
+ const blurNotification = (_a = rule.blurred) == null ? void 0 : _a.call(rule, event);
655
+ if (blurNotification) {
656
+ this._addNotification(rule, blurNotification);
657
+ }
658
+ }
659
+ });
660
+ __publicField(this, "_notifyAsync", (rule, notification) => {
661
+ this._addNotification(rule, notification);
662
+ });
663
+ this._win = win;
664
+ const _elementsToValidate = /* @__PURE__ */ new Set();
665
+ const _elementsToRemove = /* @__PURE__ */ new Set();
666
+ win.document.addEventListener("focusin", this._onFocusIn, true);
667
+ win.document.addEventListener("focusout", this._onFocusOut, true);
668
+ this._observer = new MutationObserver((mutations) => {
669
+ var _a;
670
+ for (let mutation of mutations) {
671
+ if (mutation.target.__abledomui) {
672
+ continue;
673
+ }
674
+ const added = mutation.addedNodes;
675
+ const removed = mutation.removedNodes;
676
+ const attributeName = mutation.attributeName;
677
+ if (attributeName === "id") {
678
+ this._onElementId(mutation.target, false);
679
+ continue;
680
+ }
681
+ lookUp(mutation.target);
682
+ for (let i = 0; i < added.length; i++) {
683
+ findTargets(added[i], false);
684
+ }
685
+ for (let i = 0; i < removed.length; i++) {
686
+ findTargets(removed[i], true);
687
+ }
688
+ }
689
+ (_a = this._clearValidationTimeout) == null ? void 0 : _a.call(this);
690
+ const _validationTimeout = win.setTimeout(() => {
691
+ delete this._clearValidationTimeout;
692
+ this._remove(_elementsToRemove);
693
+ this._validate(_elementsToValidate);
694
+ _elementsToRemove.clear();
695
+ _elementsToValidate.clear();
696
+ this._changedElementIds.clear();
697
+ }, 200);
698
+ this._clearValidationTimeout = () => {
699
+ win.clearTimeout(_validationTimeout);
700
+ delete this._clearValidationTimeout;
701
+ };
702
+ });
703
+ this._startFunc = () => {
704
+ delete this._startFunc;
705
+ this._observer.observe(win.document, {
706
+ childList: true,
707
+ subtree: true,
708
+ attributes: true
709
+ });
710
+ findTargets(win.document.body, false);
711
+ this._validate(_elementsToValidate);
712
+ _elementsToValidate.clear();
713
+ };
714
+ const addTarget = (node, removed) => {
715
+ if (node.nodeType !== Node.ELEMENT_NODE) {
716
+ return;
717
+ }
718
+ const id = node.id;
719
+ if (id) {
720
+ this._onElementId(node, removed);
721
+ }
722
+ if (removed) {
723
+ _elementsToRemove.add(node);
724
+ _elementsToValidate.delete(node);
725
+ } else {
726
+ _elementsToValidate.add(node);
727
+ _elementsToRemove.delete(node);
728
+ }
729
+ };
730
+ function lookUp(node) {
731
+ for (let n = node; n; n = n.parentNode) {
732
+ addTarget(n, _elementsToRemove.has(node));
733
+ }
734
+ }
735
+ function findTargets(node, removed) {
736
+ if (node.nodeType !== Node.ELEMENT_NODE) {
737
+ return;
738
+ }
739
+ addTarget(node, removed);
740
+ const walker = win.document.createTreeWalker(
741
+ node,
742
+ NodeFilter.SHOW_ELEMENT,
743
+ (node2) => {
744
+ addTarget(node2, removed);
745
+ return NodeFilter.FILTER_SKIP;
746
+ }
747
+ );
748
+ if (walker) {
749
+ while (walker.nextNode()) {
750
+ }
751
+ }
752
+ }
753
+ }
754
+ _onElementId(element, removed) {
755
+ const elementId = element.getAttribute("id");
756
+ const oldElementId = this._idByElement.get(element);
757
+ if (oldElementId) {
758
+ this._changedElementIds.add(oldElementId);
759
+ const elements = this._elementsDependingOnId.get(oldElementId);
760
+ if (elements) {
761
+ elements.delete(element);
762
+ if (elements.size === 0) {
763
+ this._elementsDependingOnId.delete(oldElementId);
764
+ }
765
+ }
766
+ }
767
+ if (elementId) {
768
+ this._changedElementIds.add(elementId);
769
+ let elements = this._elementsDependingOnId.get(elementId);
770
+ if (removed) {
771
+ this._idByElement.delete(element);
772
+ if (elements) {
773
+ elements.delete(element);
774
+ if (elements.size === 0) {
775
+ this._elementsDependingOnId.delete(elementId);
776
+ }
777
+ }
778
+ } else {
779
+ this._idByElement.set(element, elementId);
780
+ if (!elements) {
781
+ elements = /* @__PURE__ */ new Set();
782
+ this._elementsDependingOnId.set(elementId, elements);
783
+ }
784
+ elements.add(element);
785
+ }
786
+ } else {
787
+ this._idByElement.delete(element);
788
+ }
789
+ }
790
+ _addNotification(rule, notification) {
791
+ const element = notification == null ? void 0 : notification.element;
792
+ if (!notification) {
793
+ this._removeNotification(element || this._win.document.body, rule);
794
+ return;
795
+ }
796
+ let notificationUI;
797
+ if (rule.anchored && element) {
798
+ let abledomOnElement = element.__abledom;
799
+ if (!abledomOnElement) {
800
+ abledomOnElement = element.__abledom = {};
801
+ }
802
+ let notifications = abledomOnElement.notifications;
803
+ if (!notifications) {
804
+ notifications = abledomOnElement.notifications = /* @__PURE__ */ new Map();
805
+ }
806
+ notificationUI = notifications.get(rule);
807
+ if (!notificationUI) {
808
+ notificationUI = new NotificationUI(this._win, rule);
809
+ notifications.set(rule, notificationUI);
810
+ }
811
+ this._elementsWithNotifications.add(element);
812
+ } else {
813
+ notificationUI = new NotificationUI(this._win, rule);
814
+ }
815
+ notificationUI.update(notification);
816
+ }
817
+ _removeNotification(element, rule) {
818
+ var _a;
819
+ if (!rule.anchored) {
820
+ return;
821
+ }
822
+ const notifications = (_a = element.__abledom) == null ? void 0 : _a.notifications;
823
+ if (!notifications) {
824
+ return;
825
+ }
826
+ const notification = notifications.get(rule);
827
+ if (notification) {
828
+ notification.dispose();
829
+ notifications.delete(rule);
830
+ }
831
+ if (notifications.size === 0) {
832
+ this._elementsWithNotifications.delete(element);
833
+ delete element.__abledom;
834
+ }
835
+ }
836
+ _validate(elements) {
837
+ for (const id of this._changedElementIds) {
838
+ const dependingOnId = this._elementsDependingOnId.get(id);
839
+ if (dependingOnId) {
840
+ for (const element of dependingOnId) {
841
+ elements.add(element);
842
+ }
843
+ }
844
+ }
845
+ elements.forEach((element) => {
846
+ var _a, _b, _c, _d, _e;
847
+ if (isAccessibilityAffectingElement(element) || ((_a = element.__abledom) == null ? void 0 : _a.notifications)) {
848
+ const dependsOnIds = /* @__PURE__ */ new Set();
849
+ for (const rule of this._rules) {
850
+ if (!rule.validate || ((_b = rule.accept) == null ? void 0 : _b.call(rule, element)) === false) {
851
+ continue;
852
+ }
853
+ if (ValidationRule.checkExceptions(rule, element)) {
854
+ continue;
855
+ }
856
+ const validationResult = (_c = rule.validate) == null ? void 0 : _c.call(rule, element);
857
+ if (validationResult == null ? void 0 : validationResult.notification) {
858
+ this._addNotification(rule, validationResult.notification);
859
+ const ids = validationResult.dependsOnIds;
860
+ if (ids) {
861
+ for (const id of ids) {
862
+ dependsOnIds.add(id);
863
+ }
864
+ }
865
+ } else if ((_e = (_d = element.__abledom) == null ? void 0 : _d.notifications) == null ? void 0 : _e.has(rule)) {
866
+ this._removeNotification(element, rule);
867
+ }
868
+ }
869
+ this._processElementDependingOnIds(
870
+ element,
871
+ dependsOnIds.size === 0 ? null : dependsOnIds
872
+ );
873
+ }
874
+ });
875
+ }
876
+ _processElementDependingOnIds(element, ids) {
877
+ let dependsOnIds = this._dependantIdsByElement.get(element);
878
+ if (!ids && !dependsOnIds) {
879
+ return;
880
+ }
881
+ if (!dependsOnIds) {
882
+ dependsOnIds = /* @__PURE__ */ new Set();
883
+ }
884
+ if (!ids) {
885
+ ids = /* @__PURE__ */ new Set();
886
+ }
887
+ for (const id of dependsOnIds) {
888
+ if (!ids.has(id)) {
889
+ const elements = this._elementsDependingOnId.get(id);
890
+ if (elements) {
891
+ elements.delete(element);
892
+ if (elements.size === 0) {
893
+ this._elementsDependingOnId.delete(id);
894
+ }
895
+ }
896
+ }
897
+ }
898
+ for (const id of ids) {
899
+ if (!dependsOnIds.has(id)) {
900
+ dependsOnIds.add(id);
901
+ let elements = this._elementsDependingOnId.get(id);
902
+ if (!elements) {
903
+ elements = /* @__PURE__ */ new Set();
904
+ this._elementsDependingOnId.set(id, elements);
905
+ }
906
+ elements.add(element);
907
+ }
908
+ }
909
+ if (dependsOnIds.size === 0) {
910
+ this._dependantIdsByElement.delete(element);
911
+ } else {
912
+ this._dependantIdsByElement.set(element, dependsOnIds);
913
+ }
914
+ }
915
+ _remove(elements) {
916
+ elements.forEach((element) => {
917
+ var _a, _b;
918
+ const rules = [...((_b = (_a = element.__abledom) == null ? void 0 : _a.notifications) == null ? void 0 : _b.keys()) || []];
919
+ rules.forEach((rule) => this._removeNotification(element, rule));
920
+ });
921
+ }
922
+ addRule(rule) {
923
+ this._rules.push(rule);
924
+ }
925
+ removeRule(rule) {
926
+ var _a;
927
+ const index = this._rules.indexOf(rule);
928
+ if (index >= 0) {
929
+ const rule2 = this._rules[index];
930
+ this._rules.splice(index, 1);
931
+ (_a = rule2.stop) == null ? void 0 : _a.call(rule2);
932
+ }
933
+ }
934
+ start() {
935
+ var _a, _b;
936
+ if (this._isStarted) {
937
+ return;
938
+ }
939
+ this._isStarted = true;
940
+ for (const rule of this._rules) {
941
+ ValidationRule.init(rule, this._win, this._notifyAsync);
942
+ (_a = rule.start) == null ? void 0 : _a.call(rule);
943
+ }
944
+ (_b = this._startFunc) == null ? void 0 : _b.call(this);
945
+ }
946
+ dispose() {
947
+ var _a, _b;
948
+ this._win.document.addEventListener("focusin", this._onFocusIn, true);
949
+ this._win.document.addEventListener("focusout", this._onFocusOut, true);
950
+ this._remove(this._elementsWithNotifications);
951
+ this._elementsWithNotifications.clear();
952
+ this._dependantIdsByElement.clear();
953
+ this._elementsDependingOnId.clear();
954
+ this._idByElement.clear();
955
+ (_a = this._clearValidationTimeout) == null ? void 0 : _a.call(this);
956
+ for (const rule of this._rules) {
957
+ (_b = rule.stop) == null ? void 0 : _b.call(rule);
958
+ ValidationRule.dispose(rule);
959
+ }
960
+ this._rules = [];
961
+ if (this._startFunc) {
962
+ delete this._startFunc;
963
+ } else {
964
+ this._observer.disconnect();
965
+ }
966
+ }
967
+ };
968
+
969
+ // src/rules/atomic.ts
970
+ var AtomicRule = class extends ValidationRule {
971
+ constructor() {
972
+ super(...arguments);
973
+ __publicField(this, "type", 1 /* Error */);
974
+ __publicField(this, "name", "atomic");
975
+ __publicField(this, "anchored", true);
976
+ }
977
+ accept(element) {
978
+ return matchesSelector(element, focusableElementSelector);
979
+ }
980
+ validate(element) {
981
+ const parentAtomic = document.evaluate(
982
+ `ancestor::*[
983
+ @role = 'button' or
984
+ @role = 'checkbox' or
985
+ @role = 'link' or
986
+ @role = 'menuitem' or
987
+ @role = 'menuitemcheckbox' or
988
+ @role = 'menuitemradio' or
989
+ @role = 'option' or
990
+ @role = 'radio' or
991
+ @role = 'switch' or
992
+ @role = 'tab' or
993
+ @role = 'treeitem' or
994
+ self::a or
995
+ self::button or
996
+ self::input or
997
+ self::option or
998
+ self::textarea
999
+ ][1]`,
1000
+ element,
1001
+ null,
1002
+ XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
1003
+ null
1004
+ ).snapshotItem(0);
1005
+ if (parentAtomic) {
1006
+ return {
1007
+ notification: {
1008
+ id: "focusable-in-atomic",
1009
+ message: "Focusable element inside atomic focusable.",
1010
+ element,
1011
+ rel: parentAtomic
1012
+ }
1013
+ };
1014
+ }
1015
+ return null;
1016
+ }
1017
+ };
1018
+
1019
+ // src/rules/label.ts
1020
+ var _keyboardEditableInputTypes = /* @__PURE__ */ new Set([
1021
+ "text",
1022
+ "password",
1023
+ "email",
1024
+ "search",
1025
+ "tel",
1026
+ "url",
1027
+ "number",
1028
+ "date",
1029
+ "month",
1030
+ "week",
1031
+ "time",
1032
+ "datetime-local"
1033
+ ]);
1034
+ var FocusableElementLabelRule = class extends ValidationRule {
1035
+ constructor() {
1036
+ super(...arguments);
1037
+ __publicField(this, "type", 1 /* Error */);
1038
+ __publicField(this, "name", "FocusableElementLabelRule");
1039
+ __publicField(this, "anchored", true);
1040
+ }
1041
+ _isAriaHidden(element) {
1042
+ return document.evaluate(
1043
+ `ancestor-or-self::*[@aria-hidden = 'true' or @hidden]`,
1044
+ element,
1045
+ null,
1046
+ XPathResult.BOOLEAN_TYPE,
1047
+ null
1048
+ ).booleanValue;
1049
+ }
1050
+ _hasLabel(element) {
1051
+ var _a, _b;
1052
+ const labels = element.labels;
1053
+ if (labels && labels.length > 0) {
1054
+ for (let i = 0; i < labels.length; i++) {
1055
+ const label = labels[i];
1056
+ if (label.innerText.trim()) {
1057
+ return true;
1058
+ }
1059
+ }
1060
+ }
1061
+ if (element.tagName === "IMG") {
1062
+ if (element.alt.trim()) {
1063
+ return true;
1064
+ }
1065
+ }
1066
+ const labelNodes = document.evaluate(
1067
+ `(
1068
+ .//@aria-label |
1069
+ .//text() |
1070
+ .//@title |
1071
+ .//img/@alt |
1072
+ .//input[@type = 'image']/@alt |
1073
+ .//input[@type != 'hidden'][@type = 'submit' or @type = 'reset' or @type = 'button']/@value
1074
+ )[not(ancestor-or-self::*[@aria-hidden = 'true' or @hidden])]`,
1075
+ element,
1076
+ null,
1077
+ XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
1078
+ null
1079
+ );
1080
+ for (let i = 0; i < labelNodes.snapshotLength; i++) {
1081
+ const val = (_b = (_a = labelNodes.snapshotItem(i)) == null ? void 0 : _a.nodeValue) == null ? void 0 : _b.trim();
1082
+ if (val) {
1083
+ return true;
1084
+ }
1085
+ }
1086
+ return false;
1087
+ }
1088
+ accept(element) {
1089
+ return matchesSelector(element, focusableElementSelector);
1090
+ }
1091
+ validate(element) {
1092
+ var _a, _b;
1093
+ if (element.tagName === "INPUT") {
1094
+ const type = element.type;
1095
+ if (type === "hidden") {
1096
+ return null;
1097
+ }
1098
+ if (_keyboardEditableInputTypes.has(type)) {
1099
+ return null;
1100
+ }
1101
+ if (type === "image") {
1102
+ if (element.alt.trim()) {
1103
+ return null;
1104
+ }
1105
+ }
1106
+ if (type === "submit" || type === "reset" || type === "button") {
1107
+ if (element.value.trim()) {
1108
+ return null;
1109
+ }
1110
+ }
1111
+ }
1112
+ if (this._isAriaHidden(element)) {
1113
+ return null;
1114
+ }
1115
+ if (this._hasLabel(element)) {
1116
+ return null;
1117
+ }
1118
+ const labelledByNodes = document.evaluate(
1119
+ `.//@aria-labelledby[not(ancestor-or-self::*[@aria-hidden = 'true' or @hidden])]`,
1120
+ element,
1121
+ null,
1122
+ XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
1123
+ null
1124
+ );
1125
+ const labelledByValues = [];
1126
+ for (let i = 0; i < labelledByNodes.snapshotLength; i++) {
1127
+ const val = (_b = (_a = labelledByNodes.snapshotItem(i)) == null ? void 0 : _a.value) == null ? void 0 : _b.trim().split(" ");
1128
+ if (val == null ? void 0 : val.length) {
1129
+ labelledByValues.push(...val);
1130
+ }
1131
+ }
1132
+ for (const id of labelledByValues) {
1133
+ const labelElement = document.getElementById(id);
1134
+ if (labelElement && this._hasLabel(labelElement)) {
1135
+ return {
1136
+ dependsOnIds: new Set(labelledByValues)
1137
+ };
1138
+ }
1139
+ }
1140
+ return {
1141
+ notification: isElementVisible(element) ? {
1142
+ id: "focusable-element-label",
1143
+ message: "Focusable element must have a non-empty text label.",
1144
+ element
1145
+ } : void 0,
1146
+ dependsOnIds: new Set(labelledByValues)
1147
+ };
1148
+ }
1149
+ };
1150
+
1151
+ // src/rules/existingid.ts
1152
+ var ExistingIdRule = class extends ValidationRule {
1153
+ constructor() {
1154
+ super(...arguments);
1155
+ __publicField(this, "type", 1 /* Error */);
1156
+ __publicField(this, "name", "existing-id");
1157
+ __publicField(this, "anchored", true);
1158
+ }
1159
+ accept(element) {
1160
+ return element.hasAttribute("aria-labelledby") || element.hasAttribute("aria-describedby") || element.tagName === "LABEL" && !!element.htmlFor;
1161
+ }
1162
+ validate(element) {
1163
+ var _a, _b;
1164
+ const ids = [
1165
+ ...((_a = element.getAttribute("aria-labelledby")) == null ? void 0 : _a.split(" ")) || [],
1166
+ ...((_b = element.getAttribute("aria-describedby")) == null ? void 0 : _b.split(" ")) || [],
1167
+ ...element.tagName === "LABEL" ? [element.htmlFor] : []
1168
+ ].filter((id) => !!id);
1169
+ if (ids.length === 0) {
1170
+ return null;
1171
+ }
1172
+ for (const id of ids) {
1173
+ if (document.getElementById(id)) {
1174
+ return {
1175
+ dependsOnIds: new Set(ids)
1176
+ };
1177
+ }
1178
+ }
1179
+ return {
1180
+ notification: {
1181
+ id: "missing-id",
1182
+ message: `Elements with referenced ids do not extist.`,
1183
+ element
1184
+ },
1185
+ dependsOnIds: new Set(ids)
1186
+ };
1187
+ }
1188
+ };
1189
+
1190
+ // src/rules/focuslost.ts
1191
+ var FocusLostRule = class extends ValidationRule {
1192
+ constructor() {
1193
+ super(...arguments);
1194
+ __publicField(this, "type", 1 /* Error */);
1195
+ __publicField(this, "name", "focus-lost");
1196
+ __publicField(this, "anchored", false);
1197
+ __publicField(this, "_focusLostTimeout", 2e3);
1198
+ // For now reporting lost focus after 2 seconds of it being lost.
1199
+ __publicField(this, "_clearScheduledFocusLost");
1200
+ __publicField(this, "_focusedElement");
1201
+ __publicField(this, "_focusedElementPosition");
1202
+ __publicField(this, "_lastFocusStack");
1203
+ __publicField(this, "_lastBlurStack");
1204
+ __publicField(this, "_mouseEventTimer");
1205
+ __publicField(this, "_releaseMouseEvent");
1206
+ }
1207
+ _serializeElementPosition(element) {
1208
+ const position = [];
1209
+ const parentElement = element.parentElement;
1210
+ if (!parentElement) {
1211
+ return position;
1212
+ }
1213
+ for (let el = parentElement; el; el = el.parentElement) {
1214
+ const tagName = el.tagName.toLowerCase();
1215
+ position.push(tagName);
1216
+ }
1217
+ return position;
1218
+ }
1219
+ focused(event) {
1220
+ var _a;
1221
+ const target = event.target;
1222
+ (_a = this._clearScheduledFocusLost) == null ? void 0 : _a.call(this);
1223
+ if (target) {
1224
+ this._lastFocusStack = getStackTrace();
1225
+ this._focusedElement = target;
1226
+ this._focusedElementPosition = this._serializeElementPosition(target);
1227
+ }
1228
+ return null;
1229
+ }
1230
+ blurred(event) {
1231
+ var _a;
1232
+ const target = event.target;
1233
+ const win = this.window;
1234
+ (_a = this._clearScheduledFocusLost) == null ? void 0 : _a.call(this);
1235
+ if (!target || !win || event.relatedTarget || this._mouseEventTimer) {
1236
+ return null;
1237
+ }
1238
+ const targetPosition = this._focusedElement === target ? this._focusedElementPosition : void 0;
1239
+ this._lastBlurStack = getStackTrace();
1240
+ this._focusedElement = void 0;
1241
+ this._focusedElementPosition = void 0;
1242
+ const focusLostTimer = win.setTimeout(() => {
1243
+ delete this._clearScheduledFocusLost;
1244
+ if (win.document.body && (!win.document.activeElement || win.document.activeElement === win.document.body) && (!win.document.body.contains(target) || !isElementVisible(target))) {
1245
+ this.notify({
1246
+ element: target,
1247
+ id: "focus-lost",
1248
+ message: "Focus lost.",
1249
+ stack: this._lastBlurStack,
1250
+ relStack: this._lastFocusStack,
1251
+ position: targetPosition || []
1252
+ });
1253
+ }
1254
+ }, this._focusLostTimeout);
1255
+ this._clearScheduledFocusLost = () => {
1256
+ delete this._clearScheduledFocusLost;
1257
+ win.clearTimeout(focusLostTimer);
1258
+ };
1259
+ return null;
1260
+ }
1261
+ start() {
1262
+ const win = this.window;
1263
+ if (!win) {
1264
+ return;
1265
+ }
1266
+ const onMouseEvent = () => {
1267
+ if (!this._mouseEventTimer) {
1268
+ this._mouseEventTimer = win.setTimeout(() => {
1269
+ this._mouseEventTimer = void 0;
1270
+ }, 0);
1271
+ }
1272
+ };
1273
+ win.addEventListener("mousedown", onMouseEvent, true);
1274
+ win.addEventListener("mouseup", onMouseEvent, true);
1275
+ win.addEventListener("mousemove", onMouseEvent, true);
1276
+ this._releaseMouseEvent = () => {
1277
+ delete this._releaseMouseEvent;
1278
+ if (this._mouseEventTimer) {
1279
+ win.clearTimeout(this._mouseEventTimer);
1280
+ delete this._mouseEventTimer;
1281
+ }
1282
+ win.removeEventListener("mousedown", onMouseEvent, true);
1283
+ win.removeEventListener("mouseup", onMouseEvent, true);
1284
+ win.removeEventListener("mousemove", onMouseEvent, true);
1285
+ };
1286
+ }
1287
+ stop() {
1288
+ var _a, _b;
1289
+ (_a = this._releaseMouseEvent) == null ? void 0 : _a.call(this);
1290
+ (_b = this._clearScheduledFocusLost) == null ? void 0 : _b.call(this);
1291
+ this._focusedElement = void 0;
1292
+ this._focusedElementPosition = void 0;
1293
+ this._lastFocusStack = void 0;
1294
+ this._lastBlurStack = void 0;
1295
+ }
1296
+ };
1297
+
1298
+ // src/rules/badfocus.ts
1299
+ var BadFocusRule = class extends ValidationRule {
1300
+ constructor() {
1301
+ super(...arguments);
1302
+ __publicField(this, "type", 1 /* Error */);
1303
+ __publicField(this, "name", "bad-focus");
1304
+ __publicField(this, "anchored", false);
1305
+ __publicField(this, "_lastFocusStack");
1306
+ __publicField(this, "_lastBlurStack");
1307
+ __publicField(this, "_clearCheckTimer");
1308
+ }
1309
+ focused() {
1310
+ this._lastFocusStack = getStackTrace();
1311
+ return null;
1312
+ }
1313
+ blurred() {
1314
+ var _a;
1315
+ const win = this.window;
1316
+ if (!win) {
1317
+ return null;
1318
+ }
1319
+ this._lastBlurStack = getStackTrace();
1320
+ (_a = this._clearCheckTimer) == null ? void 0 : _a.call(this);
1321
+ const checkTimer = win.setTimeout(() => {
1322
+ delete this._clearCheckTimer;
1323
+ if (document.activeElement && !isElementVisible(document.activeElement)) {
1324
+ this.notify({
1325
+ id: "bad-focus",
1326
+ message: "Focused stolen by invisible element.",
1327
+ element: document.activeElement,
1328
+ stack: this._lastBlurStack,
1329
+ relStack: this._lastFocusStack
1330
+ });
1331
+ }
1332
+ }, 100);
1333
+ this._clearCheckTimer = () => {
1334
+ delete this._clearCheckTimer;
1335
+ win.clearTimeout(checkTimer);
1336
+ };
1337
+ return null;
1338
+ }
1339
+ stop() {
1340
+ var _a;
1341
+ (_a = this._clearCheckTimer) == null ? void 0 : _a.call(this);
1342
+ this._clearCheckTimer = void 0;
1343
+ this._lastFocusStack = void 0;
1344
+ this._lastBlurStack = void 0;
1345
+ }
1346
+ };
1347
+
1348
+ // src/rules/find.ts
1349
+ var FindElementRule = class extends ValidationRule {
1350
+ constructor() {
1351
+ super(...arguments);
1352
+ __publicField(this, "type", 2 /* Warning */);
1353
+ __publicField(this, "name", "find-element");
1354
+ __publicField(this, "anchored", true);
1355
+ __publicField(this, "_conditions", {});
1356
+ }
1357
+ addCondition(name, condition) {
1358
+ this._conditions[name] = condition;
1359
+ }
1360
+ removeCondition(name) {
1361
+ delete this._conditions[name];
1362
+ }
1363
+ validate(element) {
1364
+ for (const name of Object.keys(this._conditions)) {
1365
+ if (this._conditions[name](element)) {
1366
+ return {
1367
+ notification: {
1368
+ id: "find-element",
1369
+ message: `Element found: ${name}.`,
1370
+ element
1371
+ }
1372
+ };
1373
+ }
1374
+ }
1375
+ return null;
1376
+ }
1377
+ };
1378
+
1379
+ // src/rules/notify.ts
1380
+ var CustomNotifyRule = class extends ValidationRule {
1381
+ constructor() {
1382
+ super(...arguments);
1383
+ __publicField(this, "type", 3 /* Info */);
1384
+ __publicField(this, "name", "custom-notify");
1385
+ __publicField(this, "anchored", false);
1386
+ }
1387
+ customNotify(message, element) {
1388
+ this.notify({
1389
+ id: "custom-notify",
1390
+ message,
1391
+ element
1392
+ });
1393
+ }
1394
+ };
1395
+ export {
1396
+ AbleDOM,
1397
+ AtomicRule,
1398
+ BadFocusRule,
1399
+ CustomNotifyRule,
1400
+ ExistingIdRule,
1401
+ FindElementRule,
1402
+ FocusLostRule,
1403
+ FocusableElementLabelRule,
1404
+ ValidationRule,
1405
+ ValidationRuleType,
1406
+ hasAccessibilityAttribute,
1407
+ isAccessibilityAffectingElement,
1408
+ isDisplayNone,
1409
+ isElementVisible,
1410
+ matchesSelector
1411
+ };
1412
+ /*!
1413
+ * Copyright (c) Microsoft Corporation. All rights reserved.
1414
+ * Licensed under the MIT License.
1415
+ */
1416
+ //# sourceMappingURL=index.js.map