@page-agent/page-controller 1.7.0 → 1.8.0-beta.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.
@@ -1,40 +1,30 @@
1
- var __defProp = Object.defineProperty;
2
- var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
1
  function isHTMLElement(el) {
4
2
  return !!el && el.nodeType === 1;
5
3
  }
6
- __name(isHTMLElement, "isHTMLElement");
7
4
  function isInputElement(el) {
8
5
  return el?.nodeType === 1 && el.tagName === "INPUT";
9
6
  }
10
- __name(isInputElement, "isInputElement");
11
7
  function isTextAreaElement(el) {
12
8
  return el?.nodeType === 1 && el.tagName === "TEXTAREA";
13
9
  }
14
- __name(isTextAreaElement, "isTextAreaElement");
15
10
  function isSelectElement(el) {
16
11
  return el?.nodeType === 1 && el.tagName === "SELECT";
17
12
  }
18
- __name(isSelectElement, "isSelectElement");
19
13
  function isAnchorElement(el) {
20
14
  return el?.nodeType === 1 && el.tagName === "A";
21
15
  }
22
- __name(isAnchorElement, "isAnchorElement");
23
16
  function getIframeOffset(element) {
24
17
  const frame = element.ownerDocument.defaultView?.frameElement;
25
18
  if (!frame) return { x: 0, y: 0 };
26
19
  const rect = frame.getBoundingClientRect();
27
20
  return { x: rect.left, y: rect.top };
28
21
  }
29
- __name(getIframeOffset, "getIframeOffset");
30
22
  function getNativeValueSetter(element) {
31
23
  return Object.getOwnPropertyDescriptor(Object.getPrototypeOf(element), "value").set;
32
24
  }
33
- __name(getNativeValueSetter, "getNativeValueSetter");
34
25
  async function waitFor(seconds) {
35
26
  await new Promise((resolve) => setTimeout(resolve, seconds * 1e3));
36
27
  }
37
- __name(waitFor, "waitFor");
38
28
  async function movePointerToElement(element, x, y) {
39
29
  const offset = getIframeOffset(element);
40
30
  window.dispatchEvent(
@@ -44,19 +34,15 @@ async function movePointerToElement(element, x, y) {
44
34
  );
45
35
  await waitFor(0.3);
46
36
  }
47
- __name(movePointerToElement, "movePointerToElement");
48
37
  async function clickPointer() {
49
38
  window.dispatchEvent(new CustomEvent("PageAgent::ClickPointer"));
50
39
  }
51
- __name(clickPointer, "clickPointer");
52
40
  async function enablePassThrough() {
53
41
  window.dispatchEvent(new CustomEvent("PageAgent::EnablePassThrough"));
54
42
  }
55
- __name(enablePassThrough, "enablePassThrough");
56
43
  async function disablePassThrough() {
57
44
  window.dispatchEvent(new CustomEvent("PageAgent::DisablePassThrough"));
58
45
  }
59
- __name(disablePassThrough, "disablePassThrough");
60
46
  function getElementByIndex(selectorMap, index) {
61
47
  const interactiveNode = selectorMap.get(index);
62
48
  if (!interactiveNode) {
@@ -71,7 +57,6 @@ function getElementByIndex(selectorMap, index) {
71
57
  }
72
58
  return element;
73
59
  }
74
- __name(getElementByIndex, "getElementByIndex");
75
60
  let lastClickedElement = null;
76
61
  function blurLastClickedElement() {
77
62
  if (lastClickedElement) {
@@ -83,7 +68,6 @@ function blurLastClickedElement() {
83
68
  lastClickedElement = null;
84
69
  }
85
70
  }
86
- __name(blurLastClickedElement, "blurLastClickedElement");
87
71
  async function clickElement(element) {
88
72
  blurLastClickedElement();
89
73
  lastClickedElement = element;
@@ -121,7 +105,6 @@ async function clickElement(element) {
121
105
  target.click();
122
106
  await waitFor(0.2);
123
107
  }
124
- __name(clickElement, "clickElement");
125
108
  async function inputTextElement(element, text) {
126
109
  const isContentEditable = element.isContentEditable;
127
110
  if (!isInputElement(element) && !isTextAreaElement(element) && !isContentEditable) {
@@ -184,7 +167,6 @@ async function inputTextElement(element, text) {
184
167
  await waitFor(0.1);
185
168
  blurLastClickedElement();
186
169
  }
187
- __name(inputTextElement, "inputTextElement");
188
170
  async function selectOptionElement(selectElement, optionText) {
189
171
  if (!isSelectElement(selectElement)) {
190
172
  throw new Error("Element is not a select element");
@@ -198,7 +180,6 @@ async function selectOptionElement(selectElement, optionText) {
198
180
  selectElement.dispatchEvent(new Event("change", { bubbles: true }));
199
181
  await waitFor(0.1);
200
182
  }
201
- __name(selectOptionElement, "selectOptionElement");
202
183
  async function scrollIntoViewIfNeeded(element) {
203
184
  const el = element;
204
185
  if (typeof el.scrollIntoViewIfNeeded === "function") {
@@ -207,8 +188,7 @@ async function scrollIntoViewIfNeeded(element) {
207
188
  element.scrollIntoView({ behavior: "auto", block: "center", inline: "nearest" });
208
189
  }
209
190
  }
210
- __name(scrollIntoViewIfNeeded, "scrollIntoViewIfNeeded");
211
- async function scrollVertically(down, scroll_amount, element) {
191
+ async function scrollVertically(scroll_amount, element) {
212
192
  if (element) {
213
193
  const targetElement = element;
214
194
  let currentElement = targetElement;
@@ -219,7 +199,7 @@ async function scrollVertically(down, scroll_amount, element) {
219
199
  const dy2 = scroll_amount;
220
200
  while (currentElement && attempts < 10) {
221
201
  const computedStyle = window.getComputedStyle(currentElement);
222
- const hasScrollableY = /(auto|scroll|overlay)/.test(computedStyle.overflowY);
202
+ const hasScrollableY = /(auto|scroll|overlay)/.test(computedStyle.overflowY) || computedStyle.scrollbarWidth && computedStyle.scrollbarWidth !== "auto" || computedStyle.scrollbarGutter && computedStyle.scrollbarGutter !== "auto";
223
203
  const canScrollVertically = currentElement.scrollHeight > currentElement.clientHeight;
224
204
  if (hasScrollableY && canScrollVertically) {
225
205
  const beforeScroll = currentElement.scrollTop;
@@ -253,8 +233,8 @@ async function scrollVertically(down, scroll_amount, element) {
253
233
  }
254
234
  }
255
235
  const dy = scroll_amount;
256
- const bigEnough = /* @__PURE__ */ __name((el2) => el2.clientHeight >= window.innerHeight * 0.5, "bigEnough");
257
- const canScroll = /* @__PURE__ */ __name((el2) => el2 && /(auto|scroll|overlay)/.test(getComputedStyle(el2).overflowY) && el2.scrollHeight > el2.clientHeight && bigEnough(el2), "canScroll");
236
+ const bigEnough = (el2) => el2.clientHeight >= window.innerHeight * 0.5;
237
+ const canScroll = (el2) => el2 && /(auto|scroll|overlay)/.test(getComputedStyle(el2).overflowY) && el2.scrollHeight > el2.clientHeight && bigEnough(el2);
258
238
  let el = document.activeElement;
259
239
  while (el && !canScroll(el) && el !== document.body) el = el.parentElement;
260
240
  el = canScroll(el) ? el : Array.from(document.querySelectorAll("*")).find(canScroll) || document.scrollingElement || document.documentElement;
@@ -273,6 +253,8 @@ async function scrollVertically(down, scroll_amount, element) {
273
253
  if (reachedTop) return `✅ Scrolled page by ${scrolled}px. Reached the top of the page.`;
274
254
  return `✅ Scrolled page by ${scrolled}px.`;
275
255
  } else {
256
+ const warningMsg = `The document is not scrollable. Falling back to container scroll.`;
257
+ console.log(`[PageController] ${warningMsg}`);
276
258
  const scrollBefore = el.scrollTop;
277
259
  const scrollMax = el.scrollHeight - el.clientHeight;
278
260
  el.scrollBy({ top: dy, behavior: "smooth" });
@@ -280,19 +262,18 @@ async function scrollVertically(down, scroll_amount, element) {
280
262
  const scrollAfter = el.scrollTop;
281
263
  const scrolled = scrollAfter - scrollBefore;
282
264
  if (Math.abs(scrolled) < 1) {
283
- return dy > 0 ? `⚠️ Already at the bottom of container (${el.tagName}), cannot scroll down further.` : `⚠️ Already at the top of container (${el.tagName}), cannot scroll up further.`;
265
+ return dy > 0 ? `⚠️ ${warningMsg} Already at the bottom of container (${el.tagName}), cannot scroll down further.` : `⚠️ ${warningMsg} Already at the top of container (${el.tagName}), cannot scroll up further.`;
284
266
  }
285
267
  const reachedBottom = dy > 0 && scrollAfter >= scrollMax - 1;
286
268
  const reachedTop = dy < 0 && scrollAfter <= 1;
287
269
  if (reachedBottom)
288
- return `✅ Scrolled container (${el.tagName}) by ${scrolled}px. Reached the bottom.`;
270
+ return `✅ ${warningMsg} Scrolled container (${el.tagName}) by ${scrolled}px. Reached the bottom.`;
289
271
  if (reachedTop)
290
- return `✅ Scrolled container (${el.tagName}) by ${scrolled}px. Reached the top.`;
291
- return `✅ Scrolled container (${el.tagName}) by ${scrolled}px.`;
272
+ return `✅ ${warningMsg} Scrolled container (${el.tagName}) by ${scrolled}px. Reached the top.`;
273
+ return `✅ ${warningMsg} Scrolled container (${el.tagName}) by ${scrolled}px.`;
292
274
  }
293
275
  }
294
- __name(scrollVertically, "scrollVertically");
295
- async function scrollHorizontally(right, scroll_amount, element) {
276
+ async function scrollHorizontally(scroll_amount, element) {
296
277
  if (element) {
297
278
  const targetElement = element;
298
279
  let currentElement = targetElement;
@@ -300,10 +281,10 @@ async function scrollHorizontally(right, scroll_amount, element) {
300
281
  let scrolledElement = null;
301
282
  let scrollDelta = 0;
302
283
  let attempts = 0;
303
- const dx2 = right ? scroll_amount : -scroll_amount;
284
+ const dx2 = scroll_amount;
304
285
  while (currentElement && attempts < 10) {
305
286
  const computedStyle = window.getComputedStyle(currentElement);
306
- const hasScrollableX = /(auto|scroll|overlay)/.test(computedStyle.overflowX);
287
+ const hasScrollableX = /(auto|scroll|overlay)/.test(computedStyle.overflowX) || computedStyle.scrollbarWidth && computedStyle.scrollbarWidth !== "auto" || computedStyle.scrollbarGutter && computedStyle.scrollbarGutter !== "auto";
307
288
  const canScrollHorizontally = currentElement.scrollWidth > currentElement.clientWidth;
308
289
  if (hasScrollableX && canScrollHorizontally) {
309
290
  const beforeScroll = currentElement.scrollLeft;
@@ -336,9 +317,9 @@ async function scrollHorizontally(right, scroll_amount, element) {
336
317
  return `No horizontally scrollable container found for element (${targetElement.tagName})`;
337
318
  }
338
319
  }
339
- const dx = right ? scroll_amount : -scroll_amount;
340
- const bigEnough = /* @__PURE__ */ __name((el2) => el2.clientWidth >= window.innerWidth * 0.5, "bigEnough");
341
- const canScroll = /* @__PURE__ */ __name((el2) => el2 && /(auto|scroll|overlay)/.test(getComputedStyle(el2).overflowX) && el2.scrollWidth > el2.clientWidth && bigEnough(el2), "canScroll");
320
+ const dx = scroll_amount;
321
+ const bigEnough = (el2) => el2.clientWidth >= window.innerWidth * 0.5;
322
+ const canScroll = (el2) => el2 && /(auto|scroll|overlay)/.test(getComputedStyle(el2).overflowX) && el2.scrollWidth > el2.clientWidth && bigEnough(el2);
342
323
  let el = document.activeElement;
343
324
  while (el && !canScroll(el) && el !== document.body) el = el.parentElement;
344
325
  el = canScroll(el) ? el : Array.from(document.querySelectorAll("*")).find(canScroll) || document.scrollingElement || document.documentElement;
@@ -358,6 +339,8 @@ async function scrollHorizontally(right, scroll_amount, element) {
358
339
  if (reachedLeft) return `✅ Scrolled page by ${scrolled}px. Reached the left edge of the page.`;
359
340
  return `✅ Scrolled page horizontally by ${scrolled}px.`;
360
341
  } else {
342
+ const warningMsg = `The document is not scrollable. Falling back to container scroll.`;
343
+ console.log(`[PageController] ${warningMsg}`);
361
344
  const scrollBefore = el.scrollLeft;
362
345
  const scrollMax = el.scrollWidth - el.clientWidth;
363
346
  el.scrollBy({ left: dx, behavior: "smooth" });
@@ -365,19 +348,18 @@ async function scrollHorizontally(right, scroll_amount, element) {
365
348
  const scrollAfter = el.scrollLeft;
366
349
  const scrolled = scrollAfter - scrollBefore;
367
350
  if (Math.abs(scrolled) < 1) {
368
- return dx > 0 ? `⚠️ Already at the right edge of container (${el.tagName}), cannot scroll right further.` : `⚠️ Already at the left edge of container (${el.tagName}), cannot scroll left further.`;
351
+ return dx > 0 ? `⚠️ ${warningMsg} Already at the right edge of container (${el.tagName}), cannot scroll right further.` : `⚠️ ${warningMsg} Already at the left edge of container (${el.tagName}), cannot scroll left further.`;
369
352
  }
370
353
  const reachedRight = dx > 0 && scrollAfter >= scrollMax - 1;
371
354
  const reachedLeft = dx < 0 && scrollAfter <= 1;
372
355
  if (reachedRight)
373
- return `✅ Scrolled container (${el.tagName}) by ${scrolled}px. Reached the right edge.`;
356
+ return `✅ ${warningMsg} Scrolled container (${el.tagName}) by ${scrolled}px. Reached the right edge.`;
374
357
  if (reachedLeft)
375
- return `✅ Scrolled container (${el.tagName}) by ${scrolled}px. Reached the left edge.`;
376
- return `✅ Scrolled container (${el.tagName}) horizontally by ${scrolled}px.`;
358
+ return `✅ ${warningMsg} Scrolled container (${el.tagName}) by ${scrolled}px. Reached the left edge.`;
359
+ return `✅ ${warningMsg} Scrolled container (${el.tagName}) horizontally by ${scrolled}px.`;
377
360
  }
378
361
  }
379
- __name(scrollHorizontally, "scrollHorizontally");
380
- const domTree = /* @__PURE__ */ __name((args = {
362
+ const domTree = (args = {
381
363
  doHighlightElements: true,
382
364
  focusHighlightIndex: -1,
383
365
  viewportExpansion: 0,
@@ -400,16 +382,15 @@ const domTree = /* @__PURE__ */ __name((args = {
400
382
  if (!element || element.nodeType !== Node.ELEMENT_NODE) return;
401
383
  extraData.set(element, { ...extraData.get(element), ...data });
402
384
  }
403
- __name(addExtraData, "addExtraData");
404
385
  const DOM_CACHE = {
405
386
  boundingRects: /* @__PURE__ */ new WeakMap(),
406
387
  clientRects: /* @__PURE__ */ new WeakMap(),
407
388
  computedStyles: /* @__PURE__ */ new WeakMap(),
408
- clearCache: /* @__PURE__ */ __name(() => {
389
+ clearCache: () => {
409
390
  DOM_CACHE.boundingRects = /* @__PURE__ */ new WeakMap();
410
391
  DOM_CACHE.clientRects = /* @__PURE__ */ new WeakMap();
411
392
  DOM_CACHE.computedStyles = /* @__PURE__ */ new WeakMap();
412
- }, "clearCache")
393
+ }
413
394
  };
414
395
  function getCachedBoundingRect(element) {
415
396
  if (!element) return null;
@@ -422,7 +403,6 @@ const domTree = /* @__PURE__ */ __name((args = {
422
403
  }
423
404
  return rect;
424
405
  }
425
- __name(getCachedBoundingRect, "getCachedBoundingRect");
426
406
  function getCachedComputedStyle(element) {
427
407
  if (!element) return null;
428
408
  if (DOM_CACHE.computedStyles.has(element)) {
@@ -434,7 +414,6 @@ const domTree = /* @__PURE__ */ __name((args = {
434
414
  }
435
415
  return style;
436
416
  }
437
- __name(getCachedComputedStyle, "getCachedComputedStyle");
438
417
  function getCachedClientRects(element) {
439
418
  if (!element) return null;
440
419
  if (DOM_CACHE.clientRects.has(element)) {
@@ -446,7 +425,6 @@ const domTree = /* @__PURE__ */ __name((args = {
446
425
  }
447
426
  return rects;
448
427
  }
449
- __name(getCachedClientRects, "getCachedClientRects");
450
428
  const DOM_HASH_MAP = {};
451
429
  const ID = { current: 0 };
452
430
  const HIGHLIGHT_CONTAINER_ID = "playwright-highlight-container";
@@ -542,7 +520,7 @@ const domTree = /* @__PURE__ */ __name((args = {
542
520
  label.style.top = `${labelTop}px`;
543
521
  label.style.left = `${labelLeft}px`;
544
522
  fragment.appendChild(label);
545
- const updatePositions = /* @__PURE__ */ __name(() => {
523
+ const updatePositions = () => {
546
524
  const newRects = element.getClientRects();
547
525
  let newIframeOffset = { x: 0, y: 0 };
548
526
  if (parentIframe) {
@@ -588,8 +566,8 @@ const domTree = /* @__PURE__ */ __name((args = {
588
566
  } else if (label) {
589
567
  label.style.display = "none";
590
568
  }
591
- }, "updatePositions");
592
- const throttleFunction = /* @__PURE__ */ __name((func, delay) => {
569
+ };
570
+ const throttleFunction = (func, delay) => {
593
571
  let lastCall = 0;
594
572
  return (...args2) => {
595
573
  const now = performance.now();
@@ -597,16 +575,16 @@ const domTree = /* @__PURE__ */ __name((args = {
597
575
  lastCall = now;
598
576
  return func(...args2);
599
577
  };
600
- }, "throttleFunction");
578
+ };
601
579
  const throttledUpdatePositions = throttleFunction(updatePositions, 16);
602
580
  window.addEventListener("scroll", throttledUpdatePositions, true);
603
581
  window.addEventListener("resize", throttledUpdatePositions);
604
- cleanupFn = /* @__PURE__ */ __name(() => {
582
+ cleanupFn = () => {
605
583
  window.removeEventListener("scroll", throttledUpdatePositions, true);
606
584
  window.removeEventListener("resize", throttledUpdatePositions);
607
585
  overlays.forEach((overlay) => overlay.element.remove());
608
586
  if (label) label.remove();
609
- }, "cleanupFn");
587
+ };
610
588
  container.appendChild(fragment);
611
589
  return index + 1;
612
590
  } finally {
@@ -617,7 +595,6 @@ const domTree = /* @__PURE__ */ __name((args = {
617
595
  }
618
596
  }
619
597
  }
620
- __name(highlightElement, "highlightElement");
621
598
  function isScrollableElement(element) {
622
599
  if (!element || element.nodeType !== Node.ELEMENT_NODE) {
623
600
  return null;
@@ -630,9 +607,10 @@ const domTree = /* @__PURE__ */ __name((args = {
630
607
  }
631
608
  const overflowX = style.overflowX;
632
609
  const overflowY = style.overflowY;
610
+ const hasScrollbarSignal = style.scrollbarWidth && style.scrollbarWidth !== "auto" || style.scrollbarGutter && style.scrollbarGutter !== "auto";
633
611
  const scrollableX = overflowX === "auto" || overflowX === "scroll";
634
612
  const scrollableY = overflowY === "auto" || overflowY === "scroll";
635
- if (!scrollableX && !scrollableY) {
613
+ if (!scrollableX && !scrollableY && !hasScrollbarSignal) {
636
614
  return null;
637
615
  }
638
616
  const scrollWidth = element.scrollWidth - element.clientWidth;
@@ -641,10 +619,10 @@ const domTree = /* @__PURE__ */ __name((args = {
641
619
  if (scrollWidth < threshold && scrollHeight < threshold) {
642
620
  return null;
643
621
  }
644
- if (!scrollableY && scrollWidth < threshold) {
622
+ if (!scrollableY && !hasScrollbarSignal && scrollWidth < threshold) {
645
623
  return null;
646
624
  }
647
- if (!scrollableX && scrollHeight < threshold) {
625
+ if (!scrollableX && !hasScrollbarSignal && scrollHeight < threshold) {
648
626
  return null;
649
627
  }
650
628
  const distanceToTop = element.scrollTop;
@@ -661,9 +639,9 @@ const domTree = /* @__PURE__ */ __name((args = {
661
639
  scrollable: true,
662
640
  scrollData
663
641
  });
642
+ console.log("scrollData!!!", scrollData);
664
643
  return scrollData;
665
644
  }
666
- __name(isScrollableElement, "isScrollableElement");
667
645
  function isTextNodeVisible(textNode) {
668
646
  try {
669
647
  if (viewportExpansion === -1) {
@@ -715,7 +693,6 @@ const domTree = /* @__PURE__ */ __name((args = {
715
693
  return false;
716
694
  }
717
695
  }
718
- __name(isTextNodeVisible, "isTextNodeVisible");
719
696
  function isElementAccepted(element) {
720
697
  if (!element || !element.tagName) return false;
721
698
  const alwaysAccept = /* @__PURE__ */ new Set([
@@ -741,12 +718,10 @@ const domTree = /* @__PURE__ */ __name((args = {
741
718
  ]);
742
719
  return !leafElementDenyList.has(tagName);
743
720
  }
744
- __name(isElementAccepted, "isElementAccepted");
745
721
  function isElementVisible(element) {
746
722
  const style = getCachedComputedStyle(element);
747
723
  return element.offsetWidth > 0 && element.offsetHeight > 0 && style?.visibility !== "hidden" && style?.display !== "none";
748
724
  }
749
- __name(isElementVisible, "isElementVisible");
750
725
  function isInteractiveElement(element) {
751
726
  if (!element || element.nodeType !== Node.ELEMENT_NODE) {
752
727
  return false;
@@ -842,7 +817,6 @@ const domTree = /* @__PURE__ */ __name((args = {
842
817
  if (style?.cursor && interactiveCursors.has(style.cursor)) return true;
843
818
  return false;
844
819
  }
845
- __name(doesElementHaveInteractivePointer, "doesElementHaveInteractivePointer");
846
820
  let isInteractiveCursor = doesElementHaveInteractivePointer(element);
847
821
  if (isInteractiveCursor) {
848
822
  return true;
@@ -1002,7 +976,6 @@ const domTree = /* @__PURE__ */ __name((args = {
1002
976
  }
1003
977
  return false;
1004
978
  }
1005
- __name(isInteractiveElement, "isInteractiveElement");
1006
979
  function isTopElement(element) {
1007
980
  if (viewportExpansion === -1) {
1008
981
  return true;
@@ -1073,7 +1046,6 @@ const domTree = /* @__PURE__ */ __name((args = {
1073
1046
  }
1074
1047
  });
1075
1048
  }
1076
- __name(isTopElement, "isTopElement");
1077
1049
  function isInExpandedViewport(element, viewportExpansion2) {
1078
1050
  if (viewportExpansion2 === -1) {
1079
1051
  return true;
@@ -1094,7 +1066,27 @@ const domTree = /* @__PURE__ */ __name((args = {
1094
1066
  }
1095
1067
  return false;
1096
1068
  }
1097
- __name(isInExpandedViewport, "isInExpandedViewport");
1069
+ const INTERACTIVE_ARIA_ATTRS = [
1070
+ "aria-expanded",
1071
+ "aria-checked",
1072
+ "aria-selected",
1073
+ "aria-pressed",
1074
+ "aria-haspopup",
1075
+ "aria-controls",
1076
+ "aria-owns",
1077
+ "aria-activedescendant",
1078
+ "aria-valuenow",
1079
+ "aria-valuetext",
1080
+ "aria-valuemax",
1081
+ "aria-valuemin",
1082
+ "aria-autocomplete"
1083
+ ];
1084
+ function hasInteractiveAria(el) {
1085
+ for (let i = 0; i < INTERACTIVE_ARIA_ATTRS.length; i++) {
1086
+ if (el.hasAttribute(INTERACTIVE_ARIA_ATTRS[i])) return true;
1087
+ }
1088
+ return false;
1089
+ }
1098
1090
  function isInteractiveCandidate(element) {
1099
1091
  if (!element || element.nodeType !== Node.ELEMENT_NODE) return false;
1100
1092
  const tagName = element.tagName.toLowerCase();
@@ -1109,10 +1101,9 @@ const domTree = /* @__PURE__ */ __name((args = {
1109
1101
  "label"
1110
1102
  ]);
1111
1103
  if (interactiveElements.has(tagName)) return true;
1112
- const hasQuickInteractiveAttr = element.hasAttribute("onclick") || element.hasAttribute("role") || element.hasAttribute("tabindex") || element.hasAttribute("aria-") || element.hasAttribute("data-action") || element.getAttribute("contenteditable") === "true";
1104
+ const hasQuickInteractiveAttr = element.hasAttribute("onclick") || element.hasAttribute("role") || element.hasAttribute("tabindex") || hasInteractiveAria(element) || element.hasAttribute("data-action") || element.getAttribute("contenteditable") === "true";
1113
1105
  return hasQuickInteractiveAttr;
1114
1106
  }
1115
- __name(isInteractiveCandidate, "isInteractiveCandidate");
1116
1107
  const DISTINCT_INTERACTIVE_TAGS = /* @__PURE__ */ new Set([
1117
1108
  "a",
1118
1109
  "button",
@@ -1122,9 +1113,10 @@ const domTree = /* @__PURE__ */ __name((args = {
1122
1113
  "summary",
1123
1114
  "details",
1124
1115
  "label",
1125
- "option"
1116
+ "option",
1117
+ "li"
1126
1118
  ]);
1127
- const INTERACTIVE_ROLES = /* @__PURE__ */ new Set([
1119
+ const DISTINCT_INTERACTIVE_ROLES = /* @__PURE__ */ new Set([
1128
1120
  "button",
1129
1121
  "link",
1130
1122
  "menuitem",
@@ -1140,6 +1132,9 @@ const domTree = /* @__PURE__ */ __name((args = {
1140
1132
  "searchbox",
1141
1133
  "textbox",
1142
1134
  "listbox",
1135
+ "listitem",
1136
+ "treeitem",
1137
+ "row",
1143
1138
  "option",
1144
1139
  "scrollbar"
1145
1140
  ]);
@@ -1157,7 +1152,6 @@ const domTree = /* @__PURE__ */ __name((args = {
1157
1152
  const isParentBody = element.parentElement && element.parentElement.isSameNode(document.body);
1158
1153
  return (isInteractiveElement(element) || hasInteractiveAttributes || hasInteractiveClass) && hasVisibleChildren && isInKnownContainer && !isParentBody;
1159
1154
  }
1160
- __name(isHeuristicallyInteractive, "isHeuristicallyInteractive");
1161
1155
  function isElementDistinctInteraction(element) {
1162
1156
  if (!element || element.nodeType !== Node.ELEMENT_NODE) {
1163
1157
  return false;
@@ -1170,7 +1164,7 @@ const domTree = /* @__PURE__ */ __name((args = {
1170
1164
  if (DISTINCT_INTERACTIVE_TAGS.has(tagName)) {
1171
1165
  return true;
1172
1166
  }
1173
- if (role && INTERACTIVE_ROLES.has(role)) {
1167
+ if (role && DISTINCT_INTERACTIVE_ROLES.has(role)) {
1174
1168
  return true;
1175
1169
  }
1176
1170
  if (element.isContentEditable || element.getAttribute("contenteditable") === "true") {
@@ -1182,6 +1176,9 @@ const domTree = /* @__PURE__ */ __name((args = {
1182
1176
  if (element.hasAttribute("onclick") || typeof element.onclick === "function") {
1183
1177
  return true;
1184
1178
  }
1179
+ if (hasInteractiveAria(element)) {
1180
+ return true;
1181
+ }
1185
1182
  try {
1186
1183
  const getEventListenersForNode = element?.ownerDocument?.defaultView?.getEventListenersForNode || window.getEventListenersForNode;
1187
1184
  if (typeof getEventListenersForNode === "function") {
@@ -1225,9 +1222,11 @@ const domTree = /* @__PURE__ */ __name((args = {
1225
1222
  if (isHeuristicallyInteractive(element)) {
1226
1223
  return true;
1227
1224
  }
1225
+ if (extraData.get(element)?.scrollable) {
1226
+ return true;
1227
+ }
1228
1228
  return false;
1229
1229
  }
1230
- __name(isElementDistinctInteraction, "isElementDistinctInteraction");
1231
1230
  function handleHighlighting(nodeData, node, parentIframe, isParentHighlighted) {
1232
1231
  if (!nodeData.isInteractive) return false;
1233
1232
  let shouldHighlight = false;
@@ -1258,7 +1257,6 @@ const domTree = /* @__PURE__ */ __name((args = {
1258
1257
  }
1259
1258
  return false;
1260
1259
  }
1261
- __name(handleHighlighting, "handleHighlighting");
1262
1260
  function buildDomTree(node, parentIframe = null, isParentHighlighted = false) {
1263
1261
  if (!node || node.id === HIGHLIGHT_CONTAINER_ID || node.nodeType !== Node.ELEMENT_NODE && node.nodeType !== Node.TEXT_NODE) {
1264
1262
  return null;
@@ -1405,16 +1403,25 @@ const domTree = /* @__PURE__ */ __name((args = {
1405
1403
  DOM_HASH_MAP[id] = nodeData;
1406
1404
  return id;
1407
1405
  }
1408
- __name(buildDomTree, "buildDomTree");
1409
1406
  const rootId = buildDomTree(document.body);
1410
1407
  DOM_CACHE.clearCache();
1411
1408
  return { rootId, map: DOM_HASH_MAP };
1412
- }, "domTree");
1409
+ };
1413
1410
  const DEFAULT_VIEWPORT_EXPANSION = -1;
1414
1411
  function resolveViewportExpansion(viewportExpansion) {
1415
1412
  return viewportExpansion ?? DEFAULT_VIEWPORT_EXPANSION;
1416
1413
  }
1417
- __name(resolveViewportExpansion, "resolveViewportExpansion");
1414
+ const SEMANTIC_TAGS = /* @__PURE__ */ new Set([
1415
+ "nav",
1416
+ "menu",
1417
+ // 'main',
1418
+ "header",
1419
+ "footer",
1420
+ "aside",
1421
+ // 'article',
1422
+ // 'form',
1423
+ "dialog"
1424
+ ]);
1418
1425
  const newElementsCache = /* @__PURE__ */ new WeakMap();
1419
1426
  function getFlatTree(config) {
1420
1427
  const viewportExpansion = resolveViewportExpansion(config.viewportExpansion);
@@ -1457,7 +1464,6 @@ function getFlatTree(config) {
1457
1464
  }
1458
1465
  return elements;
1459
1466
  }
1460
- __name(getFlatTree, "getFlatTree");
1461
1467
  const globRegexCache = /* @__PURE__ */ new Map();
1462
1468
  function globToRegex(pattern) {
1463
1469
  let regex = globRegexCache.get(pattern);
@@ -1468,7 +1474,6 @@ function globToRegex(pattern) {
1468
1474
  }
1469
1475
  return regex;
1470
1476
  }
1471
- __name(globToRegex, "globToRegex");
1472
1477
  function matchAttributes(attrs, patterns) {
1473
1478
  const result2 = {};
1474
1479
  for (const pattern of patterns) {
@@ -1488,8 +1493,7 @@ function matchAttributes(attrs, patterns) {
1488
1493
  }
1489
1494
  return result2;
1490
1495
  }
1491
- __name(matchAttributes, "matchAttributes");
1492
- function flatTreeToString(flatTree, includeAttributes) {
1496
+ function flatTreeToString(flatTree, includeAttributes = [], keepSemanticTags = false) {
1493
1497
  const DEFAULT_INCLUDE_ATTRIBUTES = [
1494
1498
  "title",
1495
1499
  "type",
@@ -1516,14 +1520,14 @@ function flatTreeToString(flatTree, includeAttributes) {
1516
1520
  // content editable
1517
1521
  "contenteditable"
1518
1522
  ];
1519
- const includeAttrs = [...includeAttributes || [], ...DEFAULT_INCLUDE_ATTRIBUTES];
1520
- const capTextLength = /* @__PURE__ */ __name((text, maxLength) => {
1523
+ const includeAttrs = [...includeAttributes, ...DEFAULT_INCLUDE_ATTRIBUTES];
1524
+ const capTextLength = (text, maxLength) => {
1521
1525
  if (text.length > maxLength) {
1522
1526
  return text.substring(0, maxLength) + "...";
1523
1527
  }
1524
1528
  return text;
1525
- }, "capTextLength");
1526
- const buildTreeNode = /* @__PURE__ */ __name((nodeId) => {
1529
+ };
1530
+ const buildTreeNode = (nodeId) => {
1527
1531
  const node = flatTree.map[nodeId];
1528
1532
  if (!node) return null;
1529
1533
  if (node.type === "TEXT_NODE") {
@@ -1561,17 +1565,17 @@ function flatTreeToString(flatTree, includeAttributes) {
1561
1565
  extra: elementNode.extra ?? {}
1562
1566
  };
1563
1567
  }
1564
- }, "buildTreeNode");
1565
- const setParentReferences = /* @__PURE__ */ __name((node, parent = null) => {
1568
+ };
1569
+ const setParentReferences = (node, parent = null) => {
1566
1570
  node.parent = parent;
1567
1571
  for (const child of node.children) {
1568
1572
  setParentReferences(child, node);
1569
1573
  }
1570
- }, "setParentReferences");
1574
+ };
1571
1575
  const rootNode = buildTreeNode(flatTree.rootId);
1572
1576
  if (!rootNode) return "";
1573
1577
  setParentReferences(rootNode);
1574
- const hasParentWithHighlightIndex = /* @__PURE__ */ __name((node) => {
1578
+ const hasParentWithHighlightIndex = (node) => {
1575
1579
  let current = node.parent;
1576
1580
  while (current) {
1577
1581
  if (current.type === "element" && current.highlightIndex !== void 0) {
@@ -1580,11 +1584,12 @@ function flatTreeToString(flatTree, includeAttributes) {
1580
1584
  current = current.parent;
1581
1585
  }
1582
1586
  return false;
1583
- }, "hasParentWithHighlightIndex");
1584
- const processNode = /* @__PURE__ */ __name((node, depth, result22) => {
1587
+ };
1588
+ const processNode = (node, depth, result22) => {
1585
1589
  let nextDepth = depth;
1586
1590
  const depthStr = " ".repeat(depth);
1587
1591
  if (node.type === "element") {
1592
+ const isSemantic = keepSemanticTags && node.tagName && SEMANTIC_TAGS.has(node.tagName);
1588
1593
  if (node.highlightIndex !== void 0) {
1589
1594
  nextDepth += 1;
1590
1595
  const text = getAllTextTillNextClickableElement(node);
@@ -1652,9 +1657,22 @@ function flatTreeToString(flatTree, includeAttributes) {
1652
1657
  line += " />";
1653
1658
  result22.push(line);
1654
1659
  }
1660
+ const emitSemantic = isSemantic && node.highlightIndex === void 0;
1661
+ const mark = emitSemantic ? result22.length : -1;
1662
+ if (emitSemantic) {
1663
+ result22.push(`${depthStr}<${node.tagName}>`);
1664
+ nextDepth += 1;
1665
+ }
1655
1666
  for (const child of node.children) {
1656
1667
  processNode(child, nextDepth, result22);
1657
1668
  }
1669
+ if (emitSemantic) {
1670
+ if (result22.length === mark + 1) {
1671
+ result22.pop();
1672
+ } else {
1673
+ result22.push(`${depthStr}</${node.tagName}>`);
1674
+ }
1675
+ }
1658
1676
  } else if (node.type === "text") {
1659
1677
  if (hasParentWithHighlightIndex(node)) {
1660
1678
  return;
@@ -1663,15 +1681,14 @@ function flatTreeToString(flatTree, includeAttributes) {
1663
1681
  result22.push(`${depthStr}${node.text ?? ""}`);
1664
1682
  }
1665
1683
  }
1666
- }, "processNode");
1684
+ };
1667
1685
  const result2 = [];
1668
1686
  processNode(rootNode, 0, result2);
1669
1687
  return result2.join("\n");
1670
1688
  }
1671
- __name(flatTreeToString, "flatTreeToString");
1672
- const getAllTextTillNextClickableElement = /* @__PURE__ */ __name((node, maxDepth = -1) => {
1689
+ const getAllTextTillNextClickableElement = (node, maxDepth = -1) => {
1673
1690
  const textParts = [];
1674
- const collectText = /* @__PURE__ */ __name((currentNode, currentDepth) => {
1691
+ const collectText = (currentNode, currentDepth) => {
1675
1692
  if (maxDepth !== -1 && currentDepth > maxDepth) {
1676
1693
  return;
1677
1694
  }
@@ -1685,10 +1702,10 @@ const getAllTextTillNextClickableElement = /* @__PURE__ */ __name((node, maxDept
1685
1702
  collectText(child, currentDepth + 1);
1686
1703
  }
1687
1704
  }
1688
- }, "collectText");
1705
+ };
1689
1706
  collectText(node, 0);
1690
1707
  return textParts.join("\n").trim();
1691
- }, "getAllTextTillNextClickableElement");
1708
+ };
1692
1709
  function getSelectorMap(flatTree) {
1693
1710
  const selectorMap = /* @__PURE__ */ new Map();
1694
1711
  const keys = Object.keys(flatTree.map);
@@ -1700,7 +1717,6 @@ function getSelectorMap(flatTree) {
1700
1717
  }
1701
1718
  return selectorMap;
1702
1719
  }
1703
- __name(getSelectorMap, "getSelectorMap");
1704
1720
  function getElementTextMap(simplifiedHTML) {
1705
1721
  const lines = simplifiedHTML.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
1706
1722
  const elementTextMap = /* @__PURE__ */ new Map();
@@ -1714,7 +1730,6 @@ function getElementTextMap(simplifiedHTML) {
1714
1730
  }
1715
1731
  return elementTextMap;
1716
1732
  }
1717
- __name(getElementTextMap, "getElementTextMap");
1718
1733
  function cleanUpHighlights() {
1719
1734
  const cleanupFunctions = window._highlightCleanupFunctions || [];
1720
1735
  for (const cleanup of cleanupFunctions) {
@@ -1724,7 +1739,6 @@ function cleanUpHighlights() {
1724
1739
  }
1725
1740
  window._highlightCleanupFunctions = [];
1726
1741
  }
1727
- __name(cleanUpHighlights, "cleanUpHighlights");
1728
1742
  window.addEventListener("popstate", () => {
1729
1743
  cleanUpHighlights();
1730
1744
  });
@@ -1780,7 +1794,6 @@ function getPageInfo() {
1780
1794
  pixels_right
1781
1795
  };
1782
1796
  }
1783
- __name(getPageInfo, "getPageInfo");
1784
1797
  function patchReact(pageController) {
1785
1798
  const reactRootElements = document.querySelectorAll(
1786
1799
  '[data-reactroot], [data-reactid], [data-react-checksum], #root, #app, [id^="root-"], [id^="app-"], #adex-wrapper, #adex-root'
@@ -1789,8 +1802,7 @@ function patchReact(pageController) {
1789
1802
  element.setAttribute("data-page-agent-not-interactive", "true");
1790
1803
  }
1791
1804
  }
1792
- __name(patchReact, "patchReact");
1793
- const _PageController = class _PageController extends EventTarget {
1805
+ class PageController extends EventTarget {
1794
1806
  config;
1795
1807
  /** Corresponds to eval_page in browser-use */
1796
1808
  flatTree = null;
@@ -1825,7 +1837,7 @@ const _PageController = class _PageController extends EventTarget {
1825
1837
  initMask() {
1826
1838
  if (this.maskReady !== null) return;
1827
1839
  this.maskReady = (async () => {
1828
- const { SimulatorMask } = await import("./SimulatorMask-CU7szDjy.js");
1840
+ const { SimulatorMask } = await import("./SimulatorMask-BfJiQVCo.js");
1829
1841
  this.mask = new SimulatorMask();
1830
1842
  })();
1831
1843
  }
@@ -1883,13 +1895,17 @@ ${scrollHintAbove}`;
1883
1895
  cleanUpHighlights();
1884
1896
  const blacklist = [
1885
1897
  ...this.config.interactiveBlacklist || [],
1886
- ...document.querySelectorAll("[data-page-agent-not-interactive]").values()
1898
+ ...Array.from(document.querySelectorAll("[data-page-agent-not-interactive]"))
1887
1899
  ];
1888
1900
  this.flatTree = getFlatTree({
1889
1901
  ...this.config,
1890
1902
  interactiveBlacklist: blacklist
1891
1903
  });
1892
- this.simplifiedHTML = flatTreeToString(this.flatTree, this.config.includeAttributes);
1904
+ this.simplifiedHTML = flatTreeToString(
1905
+ this.flatTree,
1906
+ this.config.includeAttributes,
1907
+ this.config.keepSemanticTags
1908
+ );
1893
1909
  this.selectorMap.clear();
1894
1910
  this.selectorMap = getSelectorMap(this.flatTree);
1895
1911
  this.elementTextMap.clear();
@@ -1991,9 +2007,9 @@ ${scrollHintAbove}`;
1991
2007
  try {
1992
2008
  const { down, numPages, pixels, index } = options;
1993
2009
  this.assertIndexed();
1994
- const scrollAmount = pixels ?? numPages * (down ? 1 : -1) * window.innerHeight;
2010
+ const scrollAmount = (pixels ?? numPages * window.innerHeight) * (down ? 1 : -1);
1995
2011
  const element = index !== void 0 ? getElementByIndex(this.selectorMap, index) : null;
1996
- const message = await scrollVertically(down, scrollAmount, element);
2012
+ const message = await scrollVertically(scrollAmount, element);
1997
2013
  return {
1998
2014
  success: true,
1999
2015
  message
@@ -2014,7 +2030,7 @@ ${scrollHintAbove}`;
2014
2030
  this.assertIndexed();
2015
2031
  const scrollAmount = pixels * (right ? 1 : -1);
2016
2032
  const element = index !== void 0 ? getElementByIndex(this.selectorMap, index) : null;
2017
- const message = await scrollHorizontally(right, scrollAmount, element);
2033
+ const message = await scrollHorizontally(scrollAmount, element);
2018
2034
  return {
2019
2035
  success: true,
2020
2036
  message
@@ -2074,9 +2090,7 @@ ${scrollHintAbove}`;
2074
2090
  this.mask?.dispose();
2075
2091
  this.mask = null;
2076
2092
  }
2077
- };
2078
- __name(_PageController, "PageController");
2079
- let PageController = _PageController;
2093
+ }
2080
2094
  export {
2081
2095
  PageController,
2082
2096
  clickElement,