abledom 0.1.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -96,7 +96,7 @@ var ValidationRule = class {
96
96
  };
97
97
 
98
98
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/ui.css
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";
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: fixed;\n z-index: 100500;\n}\n\n#abledom-report :focus-visible {\n outline: 3px solid red;\n mix-blend-mode: difference;\n}\n\n#abledom-report.abledom-align-left {\n left: 10px;\n right: auto;\n}\n\n#abledom-report.abledom-align-right {\n left: auto;\n right: 10px;\n}\n\n#abledom-report.abledom-align-bottom {\n bottom: 20px;\n top: auto;\n}\n\n#abledom-report.abledom-align-top {\n /* flex-direction: column-reverse; */\n bottom: auto;\n top: 10px;\n}\n\n.abledom-menu-container {\n backdrop-filter: blur(3px);\n border-radius: 8px;\n box-shadow: 0px 0px 4px rgba(127, 127, 127, 0.5);\n display: inline-block;\n margin: 2px auto 2px 0;\n}\n\n#abledom-report.abledom-align-right .abledom-menu-container {\n margin: 2px 0 2px auto;\n}\n\n.abledom-menu {\n background-color: rgba(140, 10, 121, 0.7);\n border-radius: 8px;\n color: white;\n display: inline flex;\n font-family: Arial, Helvetica, sans-serif;\n font-size: 16px;\n line-height: 26px;\n padding: 4px;\n}\n\n.abledom-menu .notifications-count {\n margin: 0 8px;\n display: inline-block;\n}\n\n.abledom-menu .button {\n all: unset;\n color: #000;\n cursor: pointer;\n background: linear-gradient(\n 180deg,\n rgba(255, 255, 255, 1) 0%,\n rgba(200, 200, 200, 1) 100%\n );\n border-radius: 6px;\n border: 1px solid rgba(255, 255, 255, 0.4);\n box-sizing: border-box;\n line-height: 0px;\n margin-right: 4px;\n max-height: 26px;\n padding: 2px;\n text-decoration: none;\n}\n\n.abledom-menu .align-button {\n border-right-color: rgba(0, 0, 0, 0.4);\n border-radius: 0;\n margin: 0;\n}\n\n.abledom-menu .align-button:active,\n#abledom-report .pressed {\n background: linear-gradient(\n 180deg,\n rgba(130, 130, 130, 1) 0%,\n rgba(180, 180, 180, 1) 100%\n );\n}\n\n.abledom-menu .align-button-first {\n border-top-left-radius: 6px;\n border-bottom-left-radius: 6px;\n margin-left: 8px;\n}\n.abledom-menu .align-button-last {\n border-top-right-radius: 6px;\n border-bottom-right-radius: 6px;\n border-right-color: rgba(255, 255, 255, 0.4);\n}\n\n.abledom-notifications-container {\n overflow: scroll;\n max-height: calc(100vh - 100px);\n}\n\n#abledom-report.abledom-align-right .abledom-notifications-container {\n text-align: right;\n}\n\n.abledom-notification-container {\n backdrop-filter: blur(3px);\n border-radius: 8px;\n box-shadow: 0px 0px 4px rgba(127, 127, 127, 0.5);\n display: inline-flex;\n margin: 2px 0;\n}\n\n.abledom-notification {\n background-color: rgba(164, 2, 2, 0.7);\n border-radius: 8px;\n color: white;\n display: inline flex;\n font-family: Arial, Helvetica, sans-serif;\n font-size: 16px;\n line-height: 26px;\n padding: 4px;\n}\n.abledom-notification_warning {\n background-color: rgba(163, 82, 1, 0.7);\n}\n.abledom-notification_info {\n background-color: rgba(0, 0, 255, 0.7);\n}\n\n.abledom-notification .button {\n all: unset;\n color: #000;\n cursor: pointer;\n background: linear-gradient(\n 180deg,\n rgba(255, 255, 255, 1) 0%,\n rgba(200, 200, 200, 1) 100%\n );\n border-radius: 6px;\n border: 1px solid rgba(255, 255, 255, 0.4);\n box-sizing: border-box;\n line-height: 0px;\n margin-right: 4px;\n max-height: 26px;\n padding: 2px;\n text-decoration: none;\n}\n\n.abledom-notification .button:hover {\n opacity: 0.7;\n}\n\n.abledom-notification .button.close {\n background: none;\n border-color: transparent;\n color: #fff;\n margin: 0;\n}\n\n.abledom-highlight {\n background-color: yellow;\n box-sizing: border-box;\n display: none;\n opacity: 0.6;\n position: fixed;\n z-index: 100499;\n}\n\n.abledom-highlight-border1 {\n border-top: 2px solid red;\n border-bottom: 2px solid red;\n box-sizing: border-box;\n position: absolute;\n top: -2px;\n width: calc(100% + 20px);\n height: calc(100% + 4px);\n margin: 0 -10px;\n}\n\n.abledom-highlight-border2 {\n border-left: 2px solid red;\n border-right: 2px solid red;\n box-sizing: border-box;\n position: absolute;\n width: calc(100% + 4px);\n left: -2px;\n height: calc(100% + 20px);\n margin: -10px 0;\n}\n";
100
100
 
101
101
  // src/ui/domBuilder.ts
102
102
  var DOMBuilder = class {
@@ -111,6 +111,7 @@ var DOMBuilder = class {
111
111
  const parent = this._stack[0];
112
112
  const element = namespace ? (_a = this._doc) == null ? void 0 : _a.createElementNS(namespace, tagName) : (_b = this._doc) == null ? void 0 : _b.createElement(tagName);
113
113
  if (parent && element) {
114
+ element.__abledomui = true;
114
115
  if (attributes) {
115
116
  for (const [key, value] of Object.entries(attributes)) {
116
117
  if (key === "class") {
@@ -138,8 +139,12 @@ var DOMBuilder = class {
138
139
  return this;
139
140
  }
140
141
  text(text) {
141
- var _a;
142
- (_a = this._stack[0]) == null ? void 0 : _a.appendChild(document.createTextNode(text));
142
+ var _a, _b;
143
+ const textNode = (_a = this._doc) == null ? void 0 : _a.createTextNode(text);
144
+ if (textNode) {
145
+ textNode.__abledomui = true;
146
+ (_b = this._stack[0]) == null ? void 0 : _b.appendChild(textNode);
147
+ }
143
148
  return this;
144
149
  }
145
150
  element(callback) {
@@ -206,8 +211,36 @@ var reveal_default = function buildSVG4(parent) {
206
211
  return parent.firstElementChild;
207
212
  };
208
213
 
214
+ // inline-file:/Users/marata/Documents/Work/abledom/src/ui/bug.svg
215
+ var bug_default = function buildSVG5(parent) {
216
+ const builder = new DOMBuilder(parent);
217
+ builder.openTag("svg", { "width": "20", "height": "20", "viewBox": "0 0 20 20", "fill": "none", "stroke": "currentColor" }, void 0, "http://www.w3.org/2000/svg");
218
+ builder.openTag("ellipse", { "cx": "10", "cy": "12", "rx": "4", "ry": "5", "stroke-width": "1.5" }, void 0, "http://www.w3.org/2000/svg");
219
+ builder.closeTag();
220
+ builder.openTag("circle", { "cx": "10", "cy": "5.5", "r": "2", "stroke-width": "1.5" }, void 0, "http://www.w3.org/2000/svg");
221
+ builder.closeTag();
222
+ builder.openTag("line", { "x1": "6.5", "y1": "10", "x2": "3.5", "y2": "7", "stroke-width": "1.2" }, void 0, "http://www.w3.org/2000/svg");
223
+ builder.closeTag();
224
+ builder.openTag("line", { "x1": "13.5", "y1": "10", "x2": "16.5", "y2": "7", "stroke-width": "1.2" }, void 0, "http://www.w3.org/2000/svg");
225
+ builder.closeTag();
226
+ builder.openTag("line", { "x1": "6", "y1": "13", "x2": "3.5", "y2": "13", "stroke-width": "1.2" }, void 0, "http://www.w3.org/2000/svg");
227
+ builder.closeTag();
228
+ builder.openTag("line", { "x1": "14", "y1": "13", "x2": "16.5", "y2": "13", "stroke-width": "1.2" }, void 0, "http://www.w3.org/2000/svg");
229
+ builder.closeTag();
230
+ builder.openTag("line", { "x1": "6.5", "y1": "16", "x2": "3.5", "y2": "19", "stroke-width": "1.2" }, void 0, "http://www.w3.org/2000/svg");
231
+ builder.closeTag();
232
+ builder.openTag("line", { "x1": "13.5", "y1": "16", "x2": "16.5", "y2": "19", "stroke-width": "1.2" }, void 0, "http://www.w3.org/2000/svg");
233
+ builder.closeTag();
234
+ builder.openTag("line", { "x1": "9", "y1": "3.5", "x2": "7.5", "y2": "2", "stroke-width": "1.2" }, void 0, "http://www.w3.org/2000/svg");
235
+ builder.closeTag();
236
+ builder.openTag("line", { "x1": "11", "y1": "3.5", "x2": "12.5", "y2": "2", "stroke-width": "1.2" }, void 0, "http://www.w3.org/2000/svg");
237
+ builder.closeTag();
238
+ builder.closeTag();
239
+ return parent.firstElementChild;
240
+ };
241
+
209
242
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/hideall.svg
210
- var hideall_default = function buildSVG5(parent) {
243
+ var hideall_default = function buildSVG6(parent) {
211
244
  const builder = new DOMBuilder(parent);
212
245
  builder.openTag("svg", { "width": "20", "height": "20", "viewBox": "0 0 20 20", "fill": "none", "stroke": "currentColor" }, void 0, "http://www.w3.org/2000/svg");
213
246
  builder.openTag("path", { "d": "M11.44 17.5a1.67 1.67 0 0 1-2.89 0", "stroke-width": "1.5" }, void 0, "http://www.w3.org/2000/svg");
@@ -221,7 +254,7 @@ var hideall_default = function buildSVG5(parent) {
221
254
  };
222
255
 
223
256
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/muteall.svg
224
- var muteall_default = function buildSVG6(parent) {
257
+ var muteall_default = function buildSVG7(parent) {
225
258
  const builder = new DOMBuilder(parent);
226
259
  builder.openTag("svg", { "width": "20", "height": "20", "viewBox": "0 0 20 20", "fill": "none", "stroke": "currentColor" }, void 0, "http://www.w3.org/2000/svg");
227
260
  builder.openTag("path", { "d": "M11.44 17.5a1.67 1.67 0 0 1-2.89 0", "stroke-width": "1.5" }, void 0, "http://www.w3.org/2000/svg");
@@ -237,7 +270,7 @@ var muteall_default = function buildSVG6(parent) {
237
270
  };
238
271
 
239
272
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/showall.svg
240
- var showall_default = function buildSVG7(parent) {
273
+ var showall_default = function buildSVG8(parent) {
241
274
  const builder = new DOMBuilder(parent);
242
275
  builder.openTag("svg", { "width": "20", "height": "20", "viewBox": "0 0 20 20", "fill": "none", "stroke": "currentColor" }, void 0, "http://www.w3.org/2000/svg");
243
276
  builder.openTag("path", { "d": "M11.44 17.5a1.67 1.67 0 0 1-2.89 0", "stroke-width": "1.5" }, void 0, "http://www.w3.org/2000/svg");
@@ -249,7 +282,7 @@ var showall_default = function buildSVG7(parent) {
249
282
  };
250
283
 
251
284
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/aligntopleft.svg
252
- var aligntopleft_default = function buildSVG8(parent) {
285
+ var aligntopleft_default = function buildSVG9(parent) {
253
286
  const builder = new DOMBuilder(parent);
254
287
  builder.openTag("svg", { "width": "20", "height": "20", "viewBox": "0 0 20 20", "fill": "none", "stroke": "currentColor" }, void 0, "http://www.w3.org/2000/svg");
255
288
  builder.openTag("rect", { "x": "3", "y": "3", "width": "6", "height": "6", "stroke-width": "2" }, void 0, "http://www.w3.org/2000/svg");
@@ -259,7 +292,7 @@ var aligntopleft_default = function buildSVG8(parent) {
259
292
  };
260
293
 
261
294
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/aligntopright.svg
262
- var aligntopright_default = function buildSVG9(parent) {
295
+ var aligntopright_default = function buildSVG10(parent) {
263
296
  const builder = new DOMBuilder(parent);
264
297
  builder.openTag("svg", { "width": "20", "height": "20", "viewBox": "0 0 20 20", "fill": "none", "stroke": "currentColor" }, void 0, "http://www.w3.org/2000/svg");
265
298
  builder.openTag("rect", { "x": "11", "y": "3", "width": "6", "height": "6", "stroke-width": "2" }, void 0, "http://www.w3.org/2000/svg");
@@ -269,7 +302,7 @@ var aligntopright_default = function buildSVG9(parent) {
269
302
  };
270
303
 
271
304
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/alignbottomright.svg
272
- var alignbottomright_default = function buildSVG10(parent) {
305
+ var alignbottomright_default = function buildSVG11(parent) {
273
306
  const builder = new DOMBuilder(parent);
274
307
  builder.openTag("svg", { "width": "20", "height": "20", "viewBox": "0 0 20 20", "fill": "none", "stroke": "currentColor" }, void 0, "http://www.w3.org/2000/svg");
275
308
  builder.openTag("rect", { "x": "11", "y": "11", "width": "6", "height": "6", "stroke-width": "2" }, void 0, "http://www.w3.org/2000/svg");
@@ -279,7 +312,7 @@ var alignbottomright_default = function buildSVG10(parent) {
279
312
  };
280
313
 
281
314
  // inline-file:/Users/marata/Documents/Work/abledom/src/ui/alignbottomleft.svg
282
- var alignbottomleft_default = function buildSVG11(parent) {
315
+ var alignbottomleft_default = function buildSVG12(parent) {
283
316
  const builder = new DOMBuilder(parent);
284
317
  builder.openTag("svg", { "width": "20", "height": "20", "viewBox": "0 0 20 20", "fill": "none", "stroke": "currentColor" }, void 0, "http://www.w3.org/2000/svg");
285
318
  builder.openTag("rect", { "x": "3", "y": "11", "width": "6", "height": "6", "stroke-width": "2" }, void 0, "http://www.w3.org/2000/svg");
@@ -290,25 +323,21 @@ var alignbottomleft_default = function buildSVG11(parent) {
290
323
 
291
324
  // src/ui/ui.ts
292
325
  var pressedClass = "pressed";
293
- var _NotificationUI = class _NotificationUI {
294
- constructor(win, rule) {
295
- __publicField(this, "_win");
326
+ var NotificationUI = class {
327
+ constructor(win, core, rule, notificationsUI) {
328
+ __publicField(this, "_core");
329
+ __publicField(this, "_notificationsUI");
296
330
  __publicField(this, "_wrapper");
297
331
  __publicField(this, "_rule");
298
332
  __publicField(this, "_onToggle");
299
333
  __publicField(this, "isHidden", false);
300
- this._win = win;
334
+ this._core = core;
301
335
  this._rule = rule;
302
- if (!_NotificationUI._notificationsUI) {
303
- _NotificationUI._notificationsUI = new NotificationsUI(this._win);
304
- }
336
+ this._notificationsUI = notificationsUI;
305
337
  this._wrapper = win.document.createElement(
306
338
  "div"
307
339
  );
308
- if (!_NotificationUI._highlight) {
309
- _NotificationUI._highlight = new ElementHighlighter(win);
310
- }
311
- _NotificationUI._notificationsUI.addNotification(this);
340
+ notificationsUI.addNotification(this);
312
341
  }
313
342
  static setOnToggle(instance, onToggle) {
314
343
  instance._onToggle = onToggle;
@@ -317,7 +346,6 @@ var _NotificationUI = class _NotificationUI {
317
346
  return instance._wrapper;
318
347
  }
319
348
  update(notification) {
320
- const win = this._win;
321
349
  const rule = this._rule;
322
350
  const wrapper = this._wrapper;
323
351
  const element = notification.element;
@@ -329,11 +357,11 @@ var _NotificationUI = class _NotificationUI {
329
357
  (container) => {
330
358
  container.onmouseover = () => {
331
359
  var _a;
332
- element && ((_a = _NotificationUI._highlight) == null ? void 0 : _a.highlight(element));
360
+ element && ((_a = this._notificationsUI) == null ? void 0 : _a.highlight(element));
333
361
  };
334
362
  container.onmouseout = () => {
335
363
  var _a;
336
- (_a = _NotificationUI._highlight) == null ? void 0 : _a.hide();
364
+ (_a = this._notificationsUI) == null ? void 0 : _a.highlight(null);
337
365
  };
338
366
  }
339
367
  ).openTag("div", {
@@ -346,15 +374,18 @@ var _NotificationUI = class _NotificationUI {
346
374
  },
347
375
  (logButton) => {
348
376
  logButton.onclick = () => {
349
- console.error(
377
+ const { id, message, element: element2, rel, help, ...extra } = notification;
378
+ this._core.log(
350
379
  "AbleDOM: ",
380
+ "\nid:",
381
+ id,
351
382
  "\nmessage:",
352
- notification.message,
383
+ message,
353
384
  "\nelement:",
354
- element,
355
- ...notification.rel ? ["\nrelative:", notification.rel] : [],
356
- "\nnotification:",
357
- notification
385
+ element2,
386
+ ...rel ? ["\nrelative:", rel] : [],
387
+ ...help ? ["\nhelp:", help] : [],
388
+ ...Object.keys(extra).length > 0 ? ["\nextra:", extra] : []
358
389
  );
359
390
  };
360
391
  }
@@ -362,27 +393,43 @@ var _NotificationUI = class _NotificationUI {
362
393
  "button",
363
394
  {
364
395
  class: "button",
365
- title: "Reveal in Elements panel"
396
+ // title: "Reveal in Elements panel",
397
+ title: "Scroll element into view"
366
398
  },
367
399
  (revealButton) => {
368
- var _a;
369
- const hasDevTools = !!((_a = win.__ableDOMDevtools) == null ? void 0 : _a.revealElement) && false;
370
- if (hasDevTools && element && win.document.body.contains(element)) {
400
+ const element2 = notification.element;
401
+ if (element2) {
371
402
  revealButton.onclick = () => {
372
- var _a2;
373
- const revealElement = (_a2 = win.__ableDOMDevtools) == null ? void 0 : _a2.revealElement;
374
- if (revealElement && win.document.body.contains(element)) {
375
- revealElement(element).then((revealed) => {
376
- if (!revealed) {
377
- }
378
- });
379
- }
403
+ var _a;
404
+ element2.scrollIntoView();
405
+ (_a = this._notificationsUI) == null ? void 0 : _a.highlight(element2);
380
406
  };
381
407
  } else {
382
408
  revealButton.style.display = "none";
383
409
  }
384
410
  }
385
- ).element(reveal_default).closeTag().text(notification.message).openTag(
411
+ ).element(reveal_default).closeTag().openTag(
412
+ "button",
413
+ {
414
+ class: "button",
415
+ title: "Report bug"
416
+ },
417
+ (bugReportButton) => {
418
+ var _a, _b;
419
+ const bugReport = (_a = this._notificationsUI) == null ? void 0 : _a.bugReport;
420
+ if (bugReport == null ? void 0 : bugReport.isVisible(notification)) {
421
+ const title = (_b = bugReport.getTitle) == null ? void 0 : _b.call(bugReport, notification);
422
+ if (title) {
423
+ bugReportButton.title = title;
424
+ }
425
+ bugReportButton.onclick = () => {
426
+ bugReport.onClick(notification);
427
+ };
428
+ } else {
429
+ bugReportButton.style.display = "none";
430
+ }
431
+ }
432
+ ).element(bug_default).closeTag().text(notification.message).openTag(
386
433
  "a",
387
434
  {
388
435
  class: "button close",
@@ -405,7 +452,7 @@ var _NotificationUI = class _NotificationUI {
405
452
  closeButton.onclick = () => {
406
453
  var _a;
407
454
  this.toggle(false);
408
- (_a = _NotificationUI._highlight) == null ? void 0 : _a.hide();
455
+ (_a = this._notificationsUI) == null ? void 0 : _a.highlight(null);
409
456
  };
410
457
  }
411
458
  ).element(close_default).closeTag().closeTag().closeTag();
@@ -424,14 +471,12 @@ var _NotificationUI = class _NotificationUI {
424
471
  dispose() {
425
472
  var _a;
426
473
  this._wrapper.remove();
427
- (_a = _NotificationUI._notificationsUI) == null ? void 0 : _a.removeNotification(this);
474
+ (_a = this._notificationsUI) == null ? void 0 : _a.removeNotification(this);
475
+ delete this._notificationsUI;
428
476
  }
429
477
  };
430
- __publicField(_NotificationUI, "_notificationsUI");
431
- __publicField(_NotificationUI, "_highlight");
432
- var NotificationUI = _NotificationUI;
433
478
  var NotificationsUI = class {
434
- constructor(win) {
479
+ constructor(win, props) {
435
480
  __publicField(this, "_container");
436
481
  __publicField(this, "_notificationsContainer");
437
482
  __publicField(this, "_menuElement");
@@ -444,17 +489,23 @@ var NotificationsUI = class {
444
489
  __publicField(this, "_alignBottomRightButton");
445
490
  __publicField(this, "_isMuted", false);
446
491
  __publicField(this, "_notifications", /* @__PURE__ */ new Set());
447
- const container = this._container = win.document.createElement("div");
492
+ __publicField(this, "_highlighter");
493
+ __publicField(this, "bugReport");
494
+ this.bugReport = props.bugReport;
495
+ const doc = win.document;
496
+ const container = this._container = doc.createElement("div");
448
497
  container.__abledomui = true;
449
498
  container.id = "abledom-report";
450
- const style = document.createElement("style");
499
+ const style = doc.createElement("style");
451
500
  style.type = "text/css";
452
- style.appendChild(document.createTextNode(ui_default));
501
+ style.appendChild(doc.createTextNode(ui_default));
453
502
  container.appendChild(style);
454
- const notificationsContainer = this._notificationsContainer = win.document.createElement("div");
503
+ const notificationsContainer = this._notificationsContainer = doc.createElement("div");
504
+ notificationsContainer.__abledomui = true;
455
505
  notificationsContainer.className = "abledom-notifications-container";
456
506
  container.appendChild(notificationsContainer);
457
- const menuElement = this._menuElement = win.document.createElement("div");
507
+ const menuElement = this._menuElement = doc.createElement("div");
508
+ menuElement.__abledomui = true;
458
509
  menuElement.className = "abledom-menu-container";
459
510
  container.appendChild(menuElement);
460
511
  new DOMBuilder(menuElement).openTag("div", { class: "abledom-menu" }).openTag(
@@ -561,10 +612,14 @@ var NotificationsUI = class {
561
612
  };
562
613
  }
563
614
  ).element(alignbottomright_default).closeTag().closeTag();
564
- win.document.body.appendChild(container);
615
+ doc.body.appendChild(container);
616
+ this._highlighter = new ElementHighlighter(win);
565
617
  }
566
618
  setUIAlignment(alignment) {
567
619
  var _a, _b, _c, _d, _e, _f, _g, _h;
620
+ if (!this._container || !this._notificationsContainer || !this._menuElement) {
621
+ return;
622
+ }
568
623
  (_a = this._alignBottomLeftButton) == null ? void 0 : _a.classList.remove(pressedClass);
569
624
  (_b = this._alignBottomRightButton) == null ? void 0 : _b.classList.remove(pressedClass);
570
625
  (_c = this._alignTopLeftButton) == null ? void 0 : _c.classList.remove(pressedClass);
@@ -604,6 +659,9 @@ var NotificationsUI = class {
604
659
  );
605
660
  }
606
661
  _setNotificationsCount(count) {
662
+ if (!this._menuElement) {
663
+ return;
664
+ }
607
665
  const countElement = this._notificationCountElement;
608
666
  if (countElement && count > 0) {
609
667
  countElement.textContent = "";
@@ -635,6 +693,9 @@ var NotificationsUI = class {
635
693
  showAllButton.style.display = allVisible ? "none" : "block";
636
694
  }
637
695
  addNotification(notification) {
696
+ if (!this._notificationsContainer) {
697
+ throw new Error("NotificationsUI is not initialized");
698
+ }
638
699
  if (this._notifications.has(notification)) {
639
700
  return;
640
701
  }
@@ -658,6 +719,7 @@ var NotificationsUI = class {
658
719
  this._notifications.delete(notification);
659
720
  this._setNotificationsCount(this._notifications.size);
660
721
  this._setShowHideButtonsVisibility();
722
+ this.highlight(null);
661
723
  }
662
724
  hideAll() {
663
725
  this._notifications.forEach((notification) => {
@@ -671,35 +733,104 @@ var NotificationsUI = class {
671
733
  });
672
734
  this._setShowHideButtonsVisibility();
673
735
  }
736
+ highlight(element) {
737
+ var _a;
738
+ (_a = this._highlighter) == null ? void 0 : _a.highlight(element);
739
+ }
740
+ dispose() {
741
+ var _a, _b;
742
+ (_a = this._highlighter) == null ? void 0 : _a.dispose();
743
+ (_b = this._container) == null ? void 0 : _b.remove();
744
+ delete this._highlighter;
745
+ delete this._container;
746
+ delete this._notificationsContainer;
747
+ delete this._menuElement;
748
+ delete this._notificationCountElement;
749
+ delete this._showAllButton;
750
+ delete this._hideAllButton;
751
+ delete this._alignBottomLeftButton;
752
+ delete this._alignTopLeftButton;
753
+ delete this._alignTopRightButton;
754
+ delete this._alignBottomRightButton;
755
+ }
674
756
  };
675
757
  var ElementHighlighter = class {
676
758
  constructor(win) {
677
759
  __publicField(this, "_window");
678
760
  __publicField(this, "_container");
761
+ __publicField(this, "_element");
762
+ __publicField(this, "_cancelScrollTimer");
763
+ __publicField(this, "_intersectionObserver");
764
+ __publicField(this, "_onScroll", () => {
765
+ var _a;
766
+ (_a = this._cancelScrollTimer) == null ? void 0 : _a.call(this);
767
+ this._hide();
768
+ const win = this._window;
769
+ if (win) {
770
+ const scrollTimer = win.setTimeout(() => {
771
+ delete this._cancelScrollTimer;
772
+ this.highlight(this._element || null);
773
+ }, 100);
774
+ this._cancelScrollTimer = () => {
775
+ delete this._cancelScrollTimer;
776
+ win.clearTimeout(scrollTimer);
777
+ };
778
+ }
779
+ });
679
780
  this._window = win;
680
781
  const container = this._container = win.document.createElement("div");
681
782
  container.__abledomui = true;
682
783
  container.className = "abledom-highlight";
784
+ new DOMBuilder(container).openTag("div", { class: "abledom-highlight-border1" }).closeTag().openTag("div", { class: "abledom-highlight-border2" }).closeTag();
785
+ win.addEventListener("scroll", this._onScroll, true);
683
786
  }
684
787
  highlight(element) {
685
- const rect = element.getBoundingClientRect();
686
- if (rect.width === 0 || rect.height === 0) {
788
+ if (!element) {
789
+ delete this._element;
790
+ this._unobserve();
791
+ this._hide();
687
792
  return;
688
793
  }
689
794
  const win = this._window;
690
795
  const container = this._container;
691
- const style = container.style;
692
- if (container.parentElement !== win.document.body) {
693
- win.document.body.appendChild(container);
796
+ if (!win || !container) {
797
+ return;
694
798
  }
695
- style.width = `${rect.width}px`;
696
- style.height = `${rect.height}px`;
697
- style.top = `${rect.top}px`;
698
- style.left = `${rect.left}px`;
699
- container.style.display = "block";
799
+ this._element = element;
800
+ this._intersectionObserver = new IntersectionObserver(([entry]) => {
801
+ if (entry) {
802
+ const rect = entry.boundingClientRect;
803
+ const body = win.document.body;
804
+ const style = container.style;
805
+ if (container.parentElement !== body) {
806
+ body.appendChild(container);
807
+ }
808
+ style.width = `${rect.width}px`;
809
+ style.height = `${rect.height}px`;
810
+ style.top = `${rect.top}px`;
811
+ style.left = `${rect.left}px`;
812
+ container.style.display = "block";
813
+ }
814
+ });
815
+ this._intersectionObserver.observe(element);
700
816
  }
701
- hide() {
702
- this._container.style.display = "none";
817
+ dispose() {
818
+ var _a, _b, _c;
819
+ this._unobserve();
820
+ (_a = this._cancelScrollTimer) == null ? void 0 : _a.call(this);
821
+ (_b = this._window) == null ? void 0 : _b.removeEventListener("scroll", this._onScroll, true);
822
+ (_c = this._container) == null ? void 0 : _c.remove();
823
+ delete this._element;
824
+ delete this._container;
825
+ delete this._window;
826
+ }
827
+ _hide() {
828
+ this._container && (this._container.style.display = "none");
829
+ }
830
+ _unobserve() {
831
+ var _a;
832
+ (_a = this._intersectionObserver) == null ? void 0 : _a.disconnect();
833
+ delete this._intersectionObserver;
703
834
  }
704
835
  };
705
836
  function isAbleDOMUIElement(element) {
@@ -894,8 +1025,9 @@ function getStackTrace() {
894
1025
 
895
1026
  // src/core.ts
896
1027
  var AbleDOM = class {
897
- constructor(win) {
1028
+ constructor(win, props = {}) {
898
1029
  __publicField(this, "_win");
1030
+ __publicField(this, "_props");
899
1031
  __publicField(this, "_observer");
900
1032
  __publicField(this, "_clearValidationTimeout");
901
1033
  __publicField(this, "_elementsWithNotifications", /* @__PURE__ */ new Set());
@@ -906,6 +1038,7 @@ var AbleDOM = class {
906
1038
  __publicField(this, "_rules", []);
907
1039
  __publicField(this, "_startFunc");
908
1040
  __publicField(this, "_isStarted", false);
1041
+ __publicField(this, "_notificationsUI");
909
1042
  __publicField(this, "_onFocusIn", (event) => {
910
1043
  var _a;
911
1044
  const target = event.target;
@@ -935,11 +1068,18 @@ var AbleDOM = class {
935
1068
  __publicField(this, "_notifyAsync", (rule, notification) => {
936
1069
  this._addNotification(rule, notification);
937
1070
  });
1071
+ __publicField(this, "log", (...args) => {
1072
+ var _a, _b, _c, _d;
1073
+ return (_d = ((_a = this._props) == null ? void 0 : _a.log) || // In a multi-window application, just `console.error` could belong to a different window.
1074
+ ((_c = (_b = this._win) == null ? void 0 : _b.console) == null ? void 0 : _c.error)) == null ? void 0 : _d.apply(null, args);
1075
+ });
938
1076
  this._win = win;
1077
+ this._props = props;
939
1078
  const _elementsToValidate = /* @__PURE__ */ new Set();
940
1079
  const _elementsToRemove = /* @__PURE__ */ new Set();
941
- win.document.addEventListener("focusin", this._onFocusIn, true);
942
- win.document.addEventListener("focusout", this._onFocusOut, true);
1080
+ const doc = win.document;
1081
+ doc.addEventListener("focusin", this._onFocusIn, true);
1082
+ doc.addEventListener("focusout", this._onFocusOut, true);
943
1083
  this._observer = new MutationObserver((mutations) => {
944
1084
  var _a;
945
1085
  for (let mutation of mutations) {
@@ -977,12 +1117,13 @@ var AbleDOM = class {
977
1117
  });
978
1118
  this._startFunc = () => {
979
1119
  delete this._startFunc;
980
- this._observer.observe(win.document, {
1120
+ this._observer.observe(doc, {
981
1121
  childList: true,
982
1122
  subtree: true,
983
- attributes: true
1123
+ attributes: true,
1124
+ characterData: true
984
1125
  });
985
- findTargets(win.document.body, false);
1126
+ findTargets(doc.body, false);
986
1127
  this._validate(_elementsToValidate);
987
1128
  _elementsToValidate.clear();
988
1129
  };
@@ -1012,7 +1153,7 @@ var AbleDOM = class {
1012
1153
  return;
1013
1154
  }
1014
1155
  addTarget(node, removed);
1015
- const walker = win.document.createTreeWalker(
1156
+ const walker = doc.createTreeWalker(
1016
1157
  node,
1017
1158
  NodeFilter.SHOW_ELEMENT,
1018
1159
  (node2) => {
@@ -1063,6 +1204,12 @@ var AbleDOM = class {
1063
1204
  }
1064
1205
  }
1065
1206
  _addNotification(rule, notification) {
1207
+ var _a;
1208
+ if (!this._notificationsUI) {
1209
+ this._notificationsUI = new NotificationsUI(this._win, {
1210
+ bugReport: (_a = this._props) == null ? void 0 : _a.bugReport
1211
+ });
1212
+ }
1066
1213
  const element = notification == null ? void 0 : notification.element;
1067
1214
  if (!notification) {
1068
1215
  this._removeNotification(element || this._win.document.body, rule);
@@ -1080,12 +1227,22 @@ var AbleDOM = class {
1080
1227
  }
1081
1228
  notificationUI = notifications.get(rule);
1082
1229
  if (!notificationUI) {
1083
- notificationUI = new NotificationUI(this._win, rule);
1230
+ notificationUI = new NotificationUI(
1231
+ this._win,
1232
+ this,
1233
+ rule,
1234
+ this._notificationsUI
1235
+ );
1084
1236
  notifications.set(rule, notificationUI);
1085
1237
  }
1086
1238
  this._elementsWithNotifications.add(element);
1087
1239
  } else {
1088
- notificationUI = new NotificationUI(this._win, rule);
1240
+ notificationUI = new NotificationUI(
1241
+ this._win,
1242
+ this,
1243
+ rule,
1244
+ this._notificationsUI
1245
+ );
1089
1246
  }
1090
1247
  notificationUI.update(notification);
1091
1248
  }
@@ -1219,17 +1376,20 @@ var AbleDOM = class {
1219
1376
  (_b = this._startFunc) == null ? void 0 : _b.call(this);
1220
1377
  }
1221
1378
  dispose() {
1222
- var _a, _b;
1223
- this._win.document.addEventListener("focusin", this._onFocusIn, true);
1224
- this._win.document.addEventListener("focusout", this._onFocusOut, true);
1379
+ var _a, _b, _c;
1380
+ const doc = this._win.document;
1381
+ doc.addEventListener("focusin", this._onFocusIn, true);
1382
+ doc.addEventListener("focusout", this._onFocusOut, true);
1225
1383
  this._remove(this._elementsWithNotifications);
1226
1384
  this._elementsWithNotifications.clear();
1227
1385
  this._dependantIdsByElement.clear();
1228
1386
  this._elementsDependingOnId.clear();
1229
1387
  this._idByElement.clear();
1230
- (_a = this._clearValidationTimeout) == null ? void 0 : _a.call(this);
1388
+ (_a = this._notificationsUI) == null ? void 0 : _a.dispose();
1389
+ delete this._notificationsUI;
1390
+ (_b = this._clearValidationTimeout) == null ? void 0 : _b.call(this);
1231
1391
  for (const rule of this._rules) {
1232
- (_b = rule.stop) == null ? void 0 : _b.call(rule);
1392
+ (_c = rule.stop) == null ? void 0 : _c.call(rule);
1233
1393
  ValidationRule.dispose(rule);
1234
1394
  }
1235
1395
  this._rules = [];
@@ -1253,7 +1413,7 @@ var AtomicRule = class extends ValidationRule {
1253
1413
  return matchesSelector(element, focusableElementSelector);
1254
1414
  }
1255
1415
  validate(element) {
1256
- const parentAtomic = document.evaluate(
1416
+ const parentAtomic = element.ownerDocument.evaluate(
1257
1417
  `ancestor::*[
1258
1418
  @role = 'button' or
1259
1419
  @role = 'checkbox' or
@@ -1314,7 +1474,7 @@ var FocusableElementLabelRule = class extends ValidationRule {
1314
1474
  __publicField(this, "anchored", true);
1315
1475
  }
1316
1476
  _isAriaHidden(element) {
1317
- return document.evaluate(
1477
+ return element.ownerDocument.evaluate(
1318
1478
  `ancestor-or-self::*[@aria-hidden = 'true' or @hidden]`,
1319
1479
  element,
1320
1480
  null,
@@ -1341,7 +1501,7 @@ var FocusableElementLabelRule = class extends ValidationRule {
1341
1501
  if ((_a = element.textContent) == null ? void 0 : _a.trim()) {
1342
1502
  return true;
1343
1503
  }
1344
- const labelNodes = document.evaluate(
1504
+ const labelNodes = element.ownerDocument.evaluate(
1345
1505
  `(
1346
1506
  .//@aria-label |
1347
1507
  .//text() |
@@ -1368,6 +1528,7 @@ var FocusableElementLabelRule = class extends ValidationRule {
1368
1528
  }
1369
1529
  validate(element) {
1370
1530
  var _a, _b;
1531
+ const doc = element.ownerDocument;
1371
1532
  if (element.tagName === "INPUT") {
1372
1533
  const type = element.type;
1373
1534
  if (type === "hidden") {
@@ -1393,7 +1554,7 @@ var FocusableElementLabelRule = class extends ValidationRule {
1393
1554
  if (this._hasLabel(element)) {
1394
1555
  return null;
1395
1556
  }
1396
- const labelledByNodes = document.evaluate(
1557
+ const labelledByNodes = doc.evaluate(
1397
1558
  `.//@aria-labelledby[not(ancestor-or-self::*[@aria-hidden = 'true' or @hidden])]`,
1398
1559
  element,
1399
1560
  null,
@@ -1408,7 +1569,7 @@ var FocusableElementLabelRule = class extends ValidationRule {
1408
1569
  }
1409
1570
  }
1410
1571
  for (const id of labelledByValues) {
1411
- const labelElement = document.getElementById(id);
1572
+ const labelElement = doc.getElementById(id);
1412
1573
  if (labelElement && this._hasLabel(labelElement)) {
1413
1574
  return {
1414
1575
  dependsOnIds: new Set(labelledByValues)
@@ -1449,7 +1610,7 @@ var ExistingIdRule = class extends ValidationRule {
1449
1610
  return null;
1450
1611
  }
1451
1612
  for (const id of ids) {
1452
- if (document.getElementById(id)) {
1613
+ if (element.ownerDocument.getElementById(id)) {
1453
1614
  return {
1454
1615
  dependsOnIds: new Set(ids)
1455
1616
  };
@@ -1514,13 +1675,14 @@ var FocusLostRule = class extends ValidationRule {
1514
1675
  if (!target || !win || event.relatedTarget || this._mouseEventTimer) {
1515
1676
  return null;
1516
1677
  }
1678
+ const doc = win.document;
1517
1679
  const targetPosition = this._focusedElement === target ? this._focusedElementPosition : void 0;
1518
1680
  this._lastBlurStack = getStackTrace();
1519
1681
  this._focusedElement = void 0;
1520
1682
  this._focusedElementPosition = void 0;
1521
1683
  const focusLostTimer = win.setTimeout(() => {
1522
1684
  delete this._clearScheduledFocusLost;
1523
- if (win.document.body && (!win.document.activeElement || win.document.activeElement === win.document.body) && (!win.document.body.contains(target) || !isElementVisible(target))) {
1685
+ if (doc.body && (!doc.activeElement || doc.activeElement === doc.body) && (!doc.body.contains(target) || !isElementVisible(target))) {
1524
1686
  this.notify({
1525
1687
  element: target,
1526
1688
  id: "focus-lost",
@@ -1595,15 +1757,16 @@ var BadFocusRule = class extends ValidationRule {
1595
1757
  if (!win) {
1596
1758
  return null;
1597
1759
  }
1760
+ const doc = win.document;
1598
1761
  this._lastBlurStack = getStackTrace();
1599
1762
  (_a = this._clearCheckTimer) == null ? void 0 : _a.call(this);
1600
1763
  const checkTimer = win.setTimeout(() => {
1601
1764
  delete this._clearCheckTimer;
1602
- if (document.activeElement && !isElementVisible(document.activeElement)) {
1765
+ if (doc.activeElement && !isElementVisible(doc.activeElement)) {
1603
1766
  this.notify({
1604
1767
  id: "bad-focus",
1605
1768
  message: "Focused stolen by invisible element.",
1606
- element: document.activeElement,
1769
+ element: doc.activeElement,
1607
1770
  stack: this._lastBlurStack,
1608
1771
  relStack: this._lastFocusStack
1609
1772
  });