@nodebug/browser-element-finder 1.2.0 → 1.2.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.
package/README.md CHANGED
@@ -22,11 +22,11 @@ const results = ElementFinder.findElements(null, 'seleniumbase')
22
22
 
23
23
  // Count semantic element types on the screen
24
24
  const counts = ElementFinder.getElementCounts()
25
- // Returns counts for all defined non-generic types, excluding `element`
25
+ // Returns { button: { visible: 3, hidden: 0, total: 3 }, ... }
26
26
 
27
27
  // Count one semantic type
28
28
  const buttonCount = ElementFinder.getElementCounts('button')
29
- // Returns `{ button: 3 }`
29
+ // Returns `{ button: { visible: 3, hidden: 0, total: 3 } }`
30
30
 
31
31
  // Find in all frames (default)
32
32
  const results = ElementFinder.findElements('button')
@@ -225,7 +225,7 @@ The package is ESM-only (`"type": "module"`), so CommonJS `require()` examples a
225
225
  | `findElements(type, text, exact, parent)` | Find elements by type/text, returns `{ elements: [...] }` |
226
226
  | `findElementsByType(type, parent)` | Find elements by type only, returns `{ elements: [...] }` |
227
227
  | `findElementsByAttribute(value, exact, parent)` | Find elements by text/attribute, returns `{ elements: [...] }` |
228
- | `getElementCounts(type, parent)` | Count elements by semantic type, excluding generic `element` by default |
228
+ | `getElementCounts(type, parent)` | Count elements by semantic type and visibility, excluding generic `element` by default |
229
229
  | `findProbableElements(type, text, exact, parent)` | Find elements with fallback to nearby elements, returns `{ elements: [...] }` |
230
230
  | `highlight(elements, color, width)` | Highlight elements with outline |
231
231
  | `unhighlight(elements)` | Remove highlight |
@@ -418,30 +418,30 @@ Finds elements by type only. Searches all frames by default.
418
418
 
419
419
  ### `getElementCounts(type, parent)`
420
420
 
421
- Counts elements by semantic type on the current screen. Searches all frames (main document + iframes) by default.
421
+ Counts elements by semantic type and visibility on the current screen. Searches all frames (main document + iframes) by default.
422
422
 
423
423
  | Parameter | Type | Default | Description |
424
424
  | --------- | --------- | ------- | ------------------------------------------------------------------------------------------------------------- |
425
425
  | `type` | `string` | `null` | Specific element type to count. If `null`/`undefined`, returns counts for all defined types except `element`. |
426
426
  | `parent` | `Element` | `null` | Parent element to count within |
427
427
 
428
- **Returns**: `Object.<string, number>` keyed by semantic element type.
428
+ **Returns**: `Object.<string, { visible: number, hidden: number, total: number }>` keyed by semantic element type.
429
429
 
430
430
  ```javascript
431
431
  // Count all defined non-generic types
432
432
  const counts = ElementFinder.getElementCounts()
433
- // { button: 3, textbox: 2, link: 1, ... }
433
+ // { button: { visible: 3, hidden: 0, total: 3 }, textbox: { visible: 2, hidden: 0, total: 2 }, ... }
434
434
 
435
435
  // Count one type
436
436
  const buttons = ElementFinder.getElementCounts('button')
437
- // { button: 3 }
437
+ // { button: { visible: 3, hidden: 0, total: 3 } }
438
438
 
439
439
  // Count within a parent element
440
440
  const inputs = ElementFinder.getElementCounts(
441
441
  'textbox',
442
442
  document.querySelector('form'),
443
443
  )
444
- // { textbox: 2 }
444
+ // { textbox: { visible: 2, hidden: 0, total: 2 } }
445
445
  ```
446
446
 
447
447
  The generic `element` type is excluded from the all-types count so the result contains only semantic types such as `button`, `textbox`, `link`, and `table`.
package/index.js CHANGED
@@ -107,6 +107,7 @@ var ElementFinder = (() => {
107
107
  operatorAnd: /^\s*\band\b\s*/i
108
108
  };
109
109
  var MAX_RECURSION_DEPTH = 100;
110
+ var MAX_IDENTIFIABLE_TEXT_LENGTH = 25;
110
111
  var TYPE_MATCHERS = /* @__PURE__ */ new Map();
111
112
  for (const [type, expr] of Object.entries(element_definitions_default)) {
112
113
  if (expr === "true()") {
@@ -147,6 +148,21 @@ var ElementFinder = (() => {
147
148
  if (text == null) return "";
148
149
  return String(text).replace(/\s+/g, " ").trim();
149
150
  }
151
+ function shortenDescriptorText(text) {
152
+ if (text == null) return "";
153
+ const lines = String(text).split(/\r\n|\r|\n/);
154
+ let normalizedText = "";
155
+ for (let i = 0; i < lines.length; i++) {
156
+ normalizedText = normalizeDescriptorText(lines[i]);
157
+ if (normalizedText) break;
158
+ }
159
+ if (!normalizedText || normalizedText.length <= MAX_IDENTIFIABLE_TEXT_LENGTH) {
160
+ return normalizedText;
161
+ }
162
+ const shortened = normalizedText.slice(0, MAX_IDENTIFIABLE_TEXT_LENGTH);
163
+ const lastSpaceIndex = shortened.lastIndexOf(" ");
164
+ return lastSpaceIndex > 0 ? shortened.slice(0, lastSpaceIndex) : normalizedText;
165
+ }
150
166
  function getImageFilenameWithoutExtension(src) {
151
167
  const normalizedSrc = normalizeDescriptorText(src);
152
168
  if (!normalizedSrc) return "";
@@ -190,11 +206,11 @@ var ElementFinder = (() => {
190
206
  return { attributeName: attr, identifiableText };
191
207
  }
192
208
  }
193
- const directText = normalizeDescriptorText(getDirectText(el));
209
+ const directText = shortenDescriptorText(getDirectText(el));
194
210
  if (directText) {
195
211
  return { attributeName: "text", identifiableText: directText };
196
212
  }
197
- const fullText = normalizeDescriptorText(el.textContent);
213
+ const fullText = shortenDescriptorText(el.textContent);
198
214
  if (fullText) {
199
215
  return { attributeName: "text", identifiableText: fullText };
200
216
  }
@@ -546,22 +562,36 @@ var ElementFinder = (() => {
546
562
  }
547
563
  function isHidden(el) {
548
564
  if (el == null) return true;
549
- if (el.offsetWidth === 0 && el.offsetHeight === 0) {
565
+ let parent = el;
566
+ while (parent) {
567
+ if (isElementHidden(parent)) {
568
+ return true;
569
+ }
570
+ parent = parent.parentElement;
571
+ }
572
+ return false;
573
+ }
574
+ function isElementHidden(el) {
575
+ if (el.hasAttribute("hidden") || el.getAttribute("aria-hidden") === "true" || el.inert || el.offsetWidth === 0 && el.offsetHeight === 0) {
550
576
  return true;
551
577
  }
552
- try {
553
- const style = window.getComputedStyle(el);
554
- if (style.visibility === "hidden" || style.visibility === "collapse") {
578
+ if (typeof el.checkVisibility === "function") {
579
+ if (!el.checkVisibility({
580
+ checkOpacity: true,
581
+ checkVisibilityCSS: true,
582
+ contentVisibilityAuto: true
583
+ })) {
555
584
  return true;
556
585
  }
557
- if (style.display === "none") {
586
+ return false;
587
+ }
588
+ try {
589
+ const style = window.getComputedStyle(el);
590
+ if (style.visibility === "hidden" || style.visibility === "collapse" || style.display === "none" || style.opacity === "0") {
558
591
  return true;
559
592
  }
560
593
  } catch (e) {
561
594
  }
562
- if (el.hasAttribute("hidden")) {
563
- return true;
564
- }
565
595
  return false;
566
596
  }
567
597
  function findElementsByType(type = "element", parent = null, options = null) {
@@ -726,13 +756,13 @@ var ElementFinder = (() => {
726
756
  throw new TypeError(`Unknown element type: ${type}`);
727
757
  }
728
758
  console.warn(message);
729
- return { [type]: 0 };
759
+ return { [type]: { visible: 0, hidden: 0, total: 0 } };
730
760
  }
731
761
  }
732
762
  const counts = {};
733
763
  const targetTypes = hasType ? [type] : Object.keys(ELEMENT_DEFINITIONS).filter((item) => item !== "element");
734
764
  for (let i = 0; i < targetTypes.length; i++) {
735
- counts[targetTypes[i]] = 0;
765
+ counts[targetTypes[i]] = { visible: 0, hidden: 0, total: 0 };
736
766
  }
737
767
  const frames = getAllFrames(window);
738
768
  for (let i = 0; i < frames.length; i++) {
@@ -743,7 +773,9 @@ var ElementFinder = (() => {
743
773
  for (let k = 0; k < targetTypes.length; k++) {
744
774
  const targetType = targetTypes[k];
745
775
  if (matchesType(el, targetType)) {
746
- counts[targetType] += 1;
776
+ const bucket = isHidden(el) ? "hidden" : "visible";
777
+ counts[targetType][bucket] += 1;
778
+ counts[targetType].total += 1;
747
779
  }
748
780
  }
749
781
  }
package/index.min.js CHANGED
@@ -1,4 +1,4 @@
1
- var ElementFinder=(()=>{var P=Object.defineProperty;var W=Object.getOwnPropertyDescriptor;var Y=Object.getOwnPropertyNames;var X=Object.prototype.hasOwnProperty;var Z=(e,t)=>{for(var n in t)P(e,n,{get:t[n],enumerable:!0})},Q=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of Y(t))!X.call(e,r)&&r!==n&&P(e,r,{get:()=>t[r],enumerable:!(o=W(t,r))||o.enumerable});return e};var G=e=>Q(P({},"__esModule",{value:!0}),e);var we={};Z(we,{ELEMENT_DEFINITIONS:()=>p,findElements:()=>ce,findElementsByAttribute:()=>V,findElementsByType:()=>F,findProbableElements:()=>me,getAllElements:()=>y,getAllFrames:()=>x,getBoundingBox:()=>A,getElementCounts:()=>fe,getElementDescriptor:()=>le,getSearchableAttributeValues:()=>j,getSearchableAttributes:()=>te,getValidAttributes:()=>be,getValidTypes:()=>ye,highlight:()=>de,isHidden:()=>k,matchesAttribute:()=>S,matchesType:()=>g,parseCondition:()=>H,parseXPath:()=>w,pauseAnimations:()=>ge,resumeAnimations:()=>pe,setSearchableAttributes:()=>ee,splitByOperator:()=>B,unhighlight:()=>he});var D={link:"self::a or @role='link' or @href",navigation:"@role='navigation' or self::nav",heading:"@role='heading' or self::h1 or self::h2 or self::h3 or self::h4 or self::h5 or self::h6",button:"self::button or @role='button' or @type='button' or @type='submit'",checkbox:"(self::input and @type='checkbox') or @role='checkbox'",switch:"(self::input and @type='checkbox') or @role='switch' or (self::button and (contains(@class, 'switch') or @data-state))",slider:"self::input[@type='range'] or @role='slider'",datepicker:"self::input[@type='date'] or @role='date'",colorpicker:"self::input[@type='color'] or @role='color'",radio:"(self::input and @type='radio') or @role='radio'",dropdown:"(self::select[descendant::option] or @role='combobox' or @role='listbox' or contains(@class, 'dropdown') or contains(@class, 'trigger') or ancestor::*[contains(@class, 'dropdown') or @role='combobox'])",textbox:"self::textarea or (self::input and (@type='text' or @type='password' or @type='search' or @type='email' or @type='number' or @type='tel' or @type='url')) or @role='textbox'",file:"self::input and @type='file'",list:"self::ul or self::ol or @role='list'",listitem:"self::li or @role='listitem'",menu:"self::menu or @role='menu'",menuitem:"@role='menuitem'",toolbar:"@role='toolbar'",dialog:"@role='dialog' or @role='alertdialog'",table:"self::table or @role='table'",row:"self::tr or @role='row'",column:"self::td or self::th or @role='cell' or @role='gridcell' or @role='columnheader'",cell:"self::td or @role='cell' or @role='gridcell'",image:"self::img or @role='img' or @alt",element:"true()"};var R=["placeholder","value","data-value","data-test-id","data-testid","id","resource-id","name","aria-label","hint","title","tooltip","alt","src","aria-labelledby"];var b={selfWithTag:/^self::([a-zA-Z0-9-]+)(?:\[([^\]]+)\])?$/,contains:/contains\(@([a-zA-Z0-9-]+),\s*['"]([^'"]+)['"]\)/i,attrEquals:/@([a-zA-Z0-9-]+)\s*=\s*['"]([^'"]*)['"]/,attrExists:/^@([a-zA-Z0-9-]+)$/,descendant:/descendant::([a-zA-Z0-9-]+)/i,ancestor:/ancestor::\*\[([^\]]+)\]/i,operatorOr:/^\s*\bor\b\s*/i,operatorAnd:/^\s*\band\b\s*/i},v=100,C=new Map;for(let[e,t]of Object.entries(D))t==="true()"?C.set(e,()=>!0):C.set(e,n=>w(t,n));var E=R;function ee(e){if(!Array.isArray(e))throw new TypeError("attributes must be an array");E=e}function te(){return[...E]}function j(e){if(e==null||e.nodeType!==Node.ELEMENT_NODE)return{};let t={},n=E;for(let o=0;o<n.length;o++){let r=n[o],i;try{i=e.getAttribute(r)}catch(l){continue}i!=null&&i!==""&&(t[r]=i)}return t}function T(e){return e==null?"":String(e).replace(/\s+/g," ").trim()}function ne(e){let t=T(e);if(!t)return"";let n=t.split(/[?#]/)[0],o=Math.max(n.lastIndexOf("/"),n.lastIndexOf("\\")),r=o>=0?n.slice(o+1):n,i=r.lastIndexOf(".");return i>0?r.slice(0,i):r}function re(e){let t=e.getAttribute("aria-labelledby");if(!t)return"";let n=t.split(/\s+/),o=e.ownerDocument||document,r="";for(let i of n)try{let l=o.getElementById(i);if(!l)continue;let s=T(l.textContent);s&&(r=r?`${r} ${s}`:s)}catch(l){}return r}function q(e){let t=j(e),n=E;for(let i=0;i<n.length;i++){let l=n[i];if(!Object.prototype.hasOwnProperty.call(t,l))continue;let s=l==="aria-labelledby"?re(e):l==="src"?ne(t[l]):t[l],a=T(s);if(a)return{attributeName:l,identifiableText:a}}let o=T(L(e));if(o)return{attributeName:"text",identifiableText:o};let r=T(e.textContent);return r?{attributeName:"text",identifiableText:r}:null}function oe(e){if(!e||!e.ownerDocument)return null;try{let t=x(window);for(let n=0;n<t.length;n++)if(t[n].document===e.ownerDocument)return t[n].document}catch(t){}return e.ownerDocument}function ie(e,t){let n=oe(e);if(!n)return{index:1};let o=y(n),r=1,i=0;for(let l=0;l<o.length;l++){let s=o[l];if(s!==e&&(s===n.documentElement||s.tagName==="BODY"))continue;let a=q(s);!a||a.identifiableText!==t||(i++,s===e&&(r=i))}return{index:r}}function se(e){if(e==null||e.nodeType!==Node.ELEMENT_NODE)return null;let t=Object.keys(p);for(let n=0;n<t.length;n++){let o=t[n];if(o!=="element"&&g(e,o))return o}return"element"}function le(e){if(e==null||e.nodeType!==Node.ELEMENT_NODE)return{identifiableText:null,attributeName:null,index:1,type:null,tagName:null};let t=se(e),n=q(e);if(!n)return{identifiableText:null,attributeName:null,index:1,type:t,tagName:e.tagName.toLowerCase()};let o=ie(e,n.identifiableText);return{identifiableText:n.identifiableText,attributeName:n.attributeName,index:o.index,type:t,tagName:e.tagName.toLowerCase()}}function w(e,t,n=0){if(e==null||t==null)return!1;if(n>v)throw new Error("XPath expression exceeds maximum recursion depth");if(e=e.trim(),e==="true()")return!0;if(e[0]==="("&&e[e.length-1]===")"){let i=1,l=!0;for(let s=1;s<e.length-1;s++)if(e[s]==="("?i++:e[s]===")"&&i--,i===0){l=!1;break}if(l)return w(e.slice(1,-1),t,n+1)}let o=B(e,"or");if(o.length>1){for(let i of o)if(w(i,t,n+1))return!0;return!1}let r=B(e,"and");if(r.length>1){for(let i of r)if(!w(i,t,n+1))return!1;return!0}return H(e,t,n)}function B(e,t){let n=[],o=0,r="",i=!1,l="",s=t==="or"?b.operatorOr:b.operatorAnd;for(let a=0;a<e.length;a++){let f=e[a];if((f==="'"||f==='"')&&(a===0||e[a-1]!=="\\")&&(i?f===l&&(i=!1):(i=!0,l=f)),!i&&(f==="("?o++:f===")"&&o--,o===0)){let c=e.slice(a).match(s);if(c){n.push(r.trim()),a+=c[0].length-1,r="";continue}}r+=f}return r.trim()&&n.push(r.trim()),n}function H(e,t,n=0){if(e==null||t==null)return!1;e=e.trim();let o=e.match(b.selfWithTag);if(o){let f=o[1].toUpperCase();return t.tagName!==f?!1:o[2]?w(o[2],t,n+1):!0}let r=e.match(b.contains);if(r)return(t.getAttribute(r[1])||"").toLowerCase().includes(r[2].toLowerCase());let i=e.match(b.attrEquals);if(i)return t.getAttribute(i[1])===i[2];let l=e.match(b.attrExists);if(l)return t.hasAttribute(l[1]);let s=e.match(b.descendant);if(s)return t.querySelector(s[1])!==null;let a=e.match(b.ancestor);if(a){let f=t.parentElement;for(;f;){if(w(a[1],f,n+1))return!0;f=f.parentElement}return!1}return!1}var p=Object.freeze(D);function L(e){let t="";for(let n=0;n<e.childNodes.length;n++){let o=e.childNodes[n];o.nodeType===Node.TEXT_NODE&&(t+=o.textContent)}return t.trim()}function ae(e){if(e.tagName==="STYLE"||e.tagName==="SCRIPT"||e.querySelector("STYLE, SCRIPT"))return!0;let t=e.parentElement;for(;t;){if(t.tagName==="STYLE"||t.tagName==="SCRIPT")return!0;t=t.parentElement}return!1}function _(e){let t=e.getAttribute("aria-labelledby");if(!t)return"";let n=t.split(/\s+/),o="";for(let r of n)try{let i=document.getElementById(r);i&&(o+=i.textContent)}catch(i){}return o}function S(e,t,n=!1){if(e==null)return!1;if(t==null||t==="")return!0;if(ae(e))return!1;let o=E;for(let l=0;l<o.length;l++){let s=o[l],a;try{a=e.getAttribute(s)}catch(f){continue}if(a){if(s==="aria-labelledby"){if(n?a===t:a.includes(t))return!0;let f=_(e);if(f&&(n?f===t:f.includes(t)))return!0}else if(n?a===t:a.includes(t))return!0}}let r=L(e);if(n?r===t:r.includes(t))return!0;let i=e.textContent;return!!(n?i.trim()===t:i.includes(t))}function g(e,t){if(e==null)return!1;let n=C.get(t);return n?n(e):!1}function y(e=document){let t=[];if(e==null)return t;let n=e.nodeType===Node.DOCUMENT_NODE?e.documentElement:e;if(!n)return t;let o=[n];for(;o.length>0;){let r=o.pop();if(r.nodeType!==Node.ELEMENT_NODE||r.tagName==="SCRIPT"||r.tagName==="STYLE")continue;t.push(r);let i=r.children;for(let l=i.length-1;l>=0;l--)o.push(i[l]);try{if(r.shadowRoot){let l=r.shadowRoot.children;for(let s=l.length-1;s>=0;s--)o.push(l[s])}}catch(l){}}return t}function x(e=window){let t=[];try{t.push({window:e,document:e.document,isMainFrame:!0,frameIndex:-1});let n=e.document.querySelectorAll("iframe");for(let o=0;o<n.length;o++){let r=n[o];try{r.contentWindow&&r.contentDocument&&t.push({window:r.contentWindow,document:r.contentDocument,isMainFrame:!1,frameElement:r,frameIndex:o})}catch(i){i.name==="SecurityError"?console.warn("Skipping cross-origin iframe:",i.message):console.warn("Error accessing iframe:",i.message)}}}catch(n){console.warn("Error getting frames:",n.message)}return t}function A(e){let t=e.getBoundingClientRect();return{x:t.x,y:t.y,width:t.width,height:t.height,top:t.top,bottom:t.bottom,left:t.left,right:t.right,midx:t.x+t.width/2,midy:t.y+t.height/2,tagName:e.tagName.toLowerCase()}}function k(e){if(e==null||e.offsetWidth===0&&e.offsetHeight===0)return!0;try{let t=window.getComputedStyle(e);if(t.visibility==="hidden"||t.visibility==="collapse"||t.display==="none")return!0}catch(t){}return!!e.hasAttribute("hidden")}function F(e="element",t=null,n=null){if(e==null&&(e="element"),typeof e!="string")throw new TypeError(`type must be a string, got ${typeof e}`);let o=n&&n.failOnUnknownType===!0;if(e&&!p[e]){let a=`Unknown element type: ${e}. Valid types: ${Object.keys(p).join(", ")}`;if(o)throw new TypeError(`Unknown element type: ${e}`);return console.warn(a),{elements:[]}}let r=[],i=x(window);for(let a of i){let f=y(t||a.document);for(let u=0;u<f.length;u++){let c=f[u];e&&!g(c,e)||r.push({element:c,frame:a})}}let l=[];if(r.length>0){let a=new Set(r.map(u=>u.element)),f=new Set;for(let u=r.length-1;u>=0;u--){let c=r[u],m=c.element;if(!f.has(m)){l.unshift(c);let d=m.parentElement;for(;d;)a.has(d)&&f.add(d),d=d.parentElement}}}return{elements:l.map(a=>{let f=A(a.element),u=a.element.tagName.toLowerCase(),c=k(a.element);return a.frame.isMainFrame?{element:a.element,boundingBox:f,tagName:u,frameIndex:a.frame.frameIndex,isHidden:c}:{boundingBox:f,tagName:u,frameIndex:a.frame.frameIndex,isHidden:c}})}}function V(e,t=!1,n=null){if(e==null&&(e=""),typeof e!="string")throw new TypeError(`value must be a string, got ${typeof e}`);let o=[],r=x(window);for(let s of r){let a=y(n||s.document);for(let f=0;f<a.length;f++){let u=a[f];S(u,e,t)&&o.push({element:u,frame:s})}}return{elements:o.filter(s=>{let a=s.element;if(I(a,e,t))return!0;for(let u of o)if(u.element!==a&&a.contains(u.element))return!1;return!0}).map(s=>{let a=A(s.element),f=s.element.tagName.toLowerCase(),u=k(s.element);return s.frame.isMainFrame?{element:s.element,boundingBox:a,tagName:f,frameIndex:s.frame.frameIndex,isHidden:u}:{boundingBox:a,tagName:f,frameIndex:s.frame.frameIndex,isHidden:u}})}}function I(e,t,n=!1){if(t==null||t==="")return!0;let o=E;for(let i=0;i<o.length;i++){let l=o[i],s;try{s=e.getAttribute(l)}catch(a){continue}if(s){if(l==="aria-labelledby"){if(n?s===t:s.includes(t))return!0;let a=_(e);if(a&&(n?a===t:a.includes(t)))return!0}else if(n?s===t:s.includes(t))return!0}}let r=L(e);return!!(n?r===t:r.includes(t))}function fe(e=null,t=null,n=null){let o=e!=null;if(o){if(typeof e!="string")throw new TypeError(`type must be a string, got ${typeof e}`);if(!p[e]){let s=`Unknown element type: ${e}. Valid types: ${Object.keys(p).join(", ")}`;if(n&&n.failOnUnknownType===!0)throw new TypeError(`Unknown element type: ${e}`);return console.warn(s),{[e]:0}}}let r={},i=o?[e]:Object.keys(p).filter(s=>s!=="element");for(let s=0;s<i.length;s++)r[i[s]]=0;let l=x(window);for(let s=0;s<l.length;s++){let a=l[s],f=y(t||a.document);for(let u=0;u<f.length;u++){let c=f[u];for(let m=0;m<i.length;m++){let d=i[m];g(c,d)&&(r[d]+=1)}}}return r}function ce(e=null,t=null,n=!1,o=null,r=null){if(t==null&&(t=""),e!=null){if(typeof e!="string")throw new TypeError(`type must be a string, got ${typeof e}`);if(!p[e]){let f=`Unknown element type: ${e}. Valid types: ${Object.keys(p).join(", ")}`;if(r&&r.failOnUnknownType===!0)throw new TypeError(`Unknown element type: ${e}`);return console.warn(f),{elements:[]}}}if(t!==""&&typeof t!="string")throw new TypeError(`text must be a string, got ${typeof t}`);let i=[],l=x(window);for(let f of l){let u=y(o||f.document);for(let c=0;c<u.length;c++){let m=u[c];e!=null&&!g(m,e)||t!==""&&!S(m,t,n)||i.push({element:m,frame:f})}}return{elements:(t!==""?i.filter(f=>{let u=f.element;if(I(u,t,n))return!0;for(let m of i)if(m.element!==u&&u.contains(m.element))return!1;return!0}):i).map(f=>{let u=A(f.element),c=f.element.tagName.toLowerCase(),m=k(f.element);return f.frame.isMainFrame?{element:f.element,boundingBox:u,tagName:c,frameIndex:f.frame.frameIndex,isHidden:m}:{boundingBox:u,tagName:c,frameIndex:f.frame.frameIndex,isHidden:m}})}}function $(e){if(e.parentElement)return e.parentElement;try{let t=e.getRootNode();if(t&&t.host)return t.host}catch(t){}return null}function U(e){let t=$(e);if(!t)return[];if(t.shadowRoot)try{return Array.from(t.shadowRoot.children)}catch(n){return[]}return Array.from(t.children)}function ue(e,t){let n=$(e);for(;n;){if(g(n,t))return n;n=$(n)}let o=e.children||[];for(let l of o)if(g(l,t))return l;let r=U(e);for(let l of r)if(l!==e&&g(l,t))return l;for(let l of r){if(l===e)continue;let s=y(l);for(let a=0;a<s.length;a++)if(g(s[a],t))return s[a]}let i=e.parentElement;for(;i;){let l=U(i);for(let s of l)if(s!==i){if(g(s,t))return s;let a=y(s);for(let f=0;f<a.length;f++)if(g(a[f],t))return a[f]}i=i.parentElement}return null}function me(e,t,n=!1,o=null,r=null){let i=e!=null&&e!=="",l=t!=null&&t!=="";if(i&&!l)return F(e,o,r);if(!i&&l)return V(t,n,o);if(i){if(typeof e!="string")throw new TypeError(`elementType must be a string, got ${typeof e}`);if(!p[e]){let c=`Unknown element type: ${e}. Valid types: ${Object.keys(p).join(", ")}`;if(r&&r.failOnUnknownType===!0)throw new TypeError(`Unknown element type: ${e}`);return console.warn(c),{elements:[]}}}if(l&&typeof t!="string")throw new TypeError(`attributeText must be a string, got ${typeof t}`);let s=[],a=x(window);for(let c of a){let m=y(o||c.document);for(let d=0;d<m.length;d++){let h=m[d];i&&!g(h,e)||l&&!S(h,t,n)||s.push({element:h,frame:c})}}if(s.length===0&&i&&l){let c=[];for(let d of a){let h=y(o||d.document);for(let M=0;M<h.length;M++){let O=h[M];S(O,t,n)&&I(O,t,n)&&c.push({element:O,frame:d})}}let m=new Set;for(let d of c){let h=ue(d.element,e);h&&!m.has(h)&&(m.add(h),s.push({element:h,frame:d.frame}))}}return{elements:(l?s.filter(c=>{let m=c.element;if(I(m,t,n))return!0;for(let h of s)if(h.element!==m&&m.contains(h.element))return!1;return!0}):s).map(c=>{let m=A(c.element),d=c.element.tagName.toLowerCase(),h=k(c.element);return c.frame.isMainFrame?{element:c.element,boundingBox:m,tagName:d,frameIndex:c.frame.frameIndex,isHidden:h}:{boundingBox:m,tagName:d,frameIndex:c.frame.frameIndex,isHidden:h}})}}function z(e){return e?e&&e.elements&&Array.isArray(e.elements)?e.elements:Array.isArray(e)?e:[e]:[]}function de(e,t="red",n=3){let o=z(e);for(let r=0;r<o.length;r++){let i=o[r],l=i.element?i.element:i;l&&l.style&&(l.style.outline=`${n}px solid ${t}`,l.style.outlineOffset="2px",l.style.boxShadow="0 0 0 2px rgba(255, 255, 255, 0.8)",l.classList.add("elementfinder-highlighted"))}}function he(e){let t=z(e);for(let n=0;n<t.length;n++){let o=t[n],r=o.element?o.element:o;r&&r.style&&(r.style.outline="",r.style.outlineOffset="",r.style.boxShadow="",r.classList.remove("elementfinder-highlighted"))}}var N=[];function ge(){let e=new Map,t=y();for(let r of t)r&&r.style&&r.style.animationPlayState!=="paused"&&(e.set(r,{animationPlayState:r.style.animationPlayState,transitionProperty:r.style.transitionProperty,webkitAnimationPlayState:r.style.webkitAnimationPlayState,webkitTransitionProperty:r.style.webkitTransitionProperty}),r.style.animationPlayState="paused",r.style.transitionProperty="none",r.style.webkitAnimationPlayState="paused",r.style.webkitTransitionProperty="none");let n=document.getElementById("elementfinder-animation-pause");n||(n=document.createElement("style"),n.id="elementfinder-animation-pause",n.textContent=`
1
+ var ElementFinder=(()=>{var D=Object.defineProperty;var Y=Object.getOwnPropertyDescriptor;var Z=Object.getOwnPropertyNames;var G=Object.prototype.hasOwnProperty;var Q=(e,t)=>{for(var n in t)D(e,n,{get:t[n],enumerable:!0})},J=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of Z(t))!G.call(e,r)&&r!==n&&D(e,r,{get:()=>t[r],enumerable:!(o=Y(t,r))||o.enumerable});return e};var K=e=>J(D({},"__esModule",{value:!0}),e);var Te={};Q(Te,{ELEMENT_DEFINITIONS:()=>p,findElements:()=>me,findElementsByAttribute:()=>W,findElementsByType:()=>z,findProbableElements:()=>ge,getAllElements:()=>y,getAllFrames:()=>x,getBoundingBox:()=>A,getElementCounts:()=>de,getElementDescriptor:()=>fe,getSearchableAttributeValues:()=>H,getSearchableAttributes:()=>re,getValidAttributes:()=>xe,getValidTypes:()=>Ee,highlight:()=>pe,isHidden:()=>N,matchesAttribute:()=>S,matchesType:()=>g,parseCondition:()=>V,parseXPath:()=>w,pauseAnimations:()=>be,resumeAnimations:()=>we,setSearchableAttributes:()=>ne,splitByOperator:()=>B,unhighlight:()=>ye});var P={link:"self::a or @role='link' or @href",navigation:"@role='navigation' or self::nav",heading:"@role='heading' or self::h1 or self::h2 or self::h3 or self::h4 or self::h5 or self::h6",button:"self::button or @role='button' or @type='button' or @type='submit'",checkbox:"(self::input and @type='checkbox') or @role='checkbox'",switch:"(self::input and @type='checkbox') or @role='switch' or (self::button and (contains(@class, 'switch') or @data-state))",slider:"self::input[@type='range'] or @role='slider'",datepicker:"self::input[@type='date'] or @role='date'",colorpicker:"self::input[@type='color'] or @role='color'",radio:"(self::input and @type='radio') or @role='radio'",dropdown:"(self::select[descendant::option] or @role='combobox' or @role='listbox' or contains(@class, 'dropdown') or contains(@class, 'trigger') or ancestor::*[contains(@class, 'dropdown') or @role='combobox'])",textbox:"self::textarea or (self::input and (@type='text' or @type='password' or @type='search' or @type='email' or @type='number' or @type='tel' or @type='url')) or @role='textbox'",file:"self::input and @type='file'",list:"self::ul or self::ol or @role='list'",listitem:"self::li or @role='listitem'",menu:"self::menu or @role='menu'",menuitem:"@role='menuitem'",toolbar:"@role='toolbar'",dialog:"@role='dialog' or @role='alertdialog'",table:"self::table or @role='table'",row:"self::tr or @role='row'",column:"self::td or self::th or @role='cell' or @role='gridcell' or @role='columnheader'",cell:"self::td or @role='cell' or @role='gridcell'",image:"self::img or @role='img' or @alt",element:"true()"};var R=["placeholder","value","data-value","data-test-id","data-testid","id","resource-id","name","aria-label","hint","title","tooltip","alt","src","aria-labelledby"];var b={selfWithTag:/^self::([a-zA-Z0-9-]+)(?:\[([^\]]+)\])?$/,contains:/contains\(@([a-zA-Z0-9-]+),\s*['"]([^'"]+)['"]\)/i,attrEquals:/@([a-zA-Z0-9-]+)\s*=\s*['"]([^'"]*)['"]/,attrExists:/^@([a-zA-Z0-9-]+)$/,descendant:/descendant::([a-zA-Z0-9-]+)/i,ancestor:/ancestor::\*\[([^\]]+)\]/i,operatorOr:/^\s*\bor\b\s*/i,operatorAnd:/^\s*\band\b\s*/i},te=100,U=25,C=new Map;for(let[e,t]of Object.entries(P))t==="true()"?C.set(e,()=>!0):C.set(e,n=>w(t,n));var E=R;function ne(e){if(!Array.isArray(e))throw new TypeError("attributes must be an array");E=e}function re(){return[...E]}function H(e){if(e==null||e.nodeType!==Node.ELEMENT_NODE)return{};let t={},n=E;for(let o=0;o<n.length;o++){let r=n[o],i;try{i=e.getAttribute(r)}catch(l){continue}i!=null&&i!==""&&(t[r]=i)}return t}function I(e){return e==null?"":String(e).replace(/\s+/g," ").trim()}function j(e){if(e==null)return"";let t=String(e).split(/\r\n|\r|\n/),n="";for(let i=0;i<t.length&&(n=I(t[i]),!n);i++);if(!n||n.length<=U)return n;let o=n.slice(0,U),r=o.lastIndexOf(" ");return r>0?o.slice(0,r):n}function oe(e){let t=I(e);if(!t)return"";let n=t.split(/[?#]/)[0],o=Math.max(n.lastIndexOf("/"),n.lastIndexOf("\\")),r=o>=0?n.slice(o+1):n,i=r.lastIndexOf(".");return i>0?r.slice(0,i):r}function ie(e){let t=e.getAttribute("aria-labelledby");if(!t)return"";let n=t.split(/\s+/),o=e.ownerDocument||document,r="";for(let i of n)try{let l=o.getElementById(i);if(!l)continue;let s=I(l.textContent);s&&(r=r?`${r} ${s}`:s)}catch(l){}return r}function _(e){let t=H(e),n=E;for(let i=0;i<n.length;i++){let l=n[i];if(!Object.prototype.hasOwnProperty.call(t,l))continue;let s=l==="aria-labelledby"?ie(e):l==="src"?oe(t[l]):t[l],a=I(s);if(a)return{attributeName:l,identifiableText:a}}let o=j($(e));if(o)return{attributeName:"text",identifiableText:o};let r=j(e.textContent);return r?{attributeName:"text",identifiableText:r}:null}function se(e){if(!e||!e.ownerDocument)return null;try{let t=x(window);for(let n=0;n<t.length;n++)if(t[n].document===e.ownerDocument)return t[n].document}catch(t){}return e.ownerDocument}function le(e,t){let n=se(e);if(!n)return{index:1};let o=y(n),r=1,i=0;for(let l=0;l<o.length;l++){let s=o[l];if(s!==e&&(s===n.documentElement||s.tagName==="BODY"))continue;let a=_(s);!a||a.identifiableText!==t||(i++,s===e&&(r=i))}return{index:r}}function ae(e){if(e==null||e.nodeType!==Node.ELEMENT_NODE)return null;let t=Object.keys(p);for(let n=0;n<t.length;n++){let o=t[n];if(o!=="element"&&g(e,o))return o}return"element"}function fe(e){if(e==null||e.nodeType!==Node.ELEMENT_NODE)return{identifiableText:null,attributeName:null,index:1,type:null,tagName:null};let t=ae(e),n=_(e);if(!n)return{identifiableText:null,attributeName:null,index:1,type:t,tagName:e.tagName.toLowerCase()};let o=le(e,n.identifiableText);return{identifiableText:n.identifiableText,attributeName:n.attributeName,index:o.index,type:t,tagName:e.tagName.toLowerCase()}}function w(e,t,n=0){if(e==null||t==null)return!1;if(n>te)throw new Error("XPath expression exceeds maximum recursion depth");if(e=e.trim(),e==="true()")return!0;if(e[0]==="("&&e[e.length-1]===")"){let i=1,l=!0;for(let s=1;s<e.length-1;s++)if(e[s]==="("?i++:e[s]===")"&&i--,i===0){l=!1;break}if(l)return w(e.slice(1,-1),t,n+1)}let o=B(e,"or");if(o.length>1){for(let i of o)if(w(i,t,n+1))return!0;return!1}let r=B(e,"and");if(r.length>1){for(let i of r)if(!w(i,t,n+1))return!1;return!0}return V(e,t,n)}function B(e,t){let n=[],o=0,r="",i=!1,l="",s=t==="or"?b.operatorOr:b.operatorAnd;for(let a=0;a<e.length;a++){let f=e[a];if((f==="'"||f==='"')&&(a===0||e[a-1]!=="\\")&&(i?f===l&&(i=!1):(i=!0,l=f)),!i&&(f==="("?o++:f===")"&&o--,o===0)){let c=e.slice(a).match(s);if(c){n.push(r.trim()),a+=c[0].length-1,r="";continue}}r+=f}return r.trim()&&n.push(r.trim()),n}function V(e,t,n=0){if(e==null||t==null)return!1;e=e.trim();let o=e.match(b.selfWithTag);if(o){let f=o[1].toUpperCase();return t.tagName!==f?!1:o[2]?w(o[2],t,n+1):!0}let r=e.match(b.contains);if(r)return(t.getAttribute(r[1])||"").toLowerCase().includes(r[2].toLowerCase());let i=e.match(b.attrEquals);if(i)return t.getAttribute(i[1])===i[2];let l=e.match(b.attrExists);if(l)return t.hasAttribute(l[1]);let s=e.match(b.descendant);if(s)return t.querySelector(s[1])!==null;let a=e.match(b.ancestor);if(a){let f=t.parentElement;for(;f;){if(w(a[1],f,n+1))return!0;f=f.parentElement}return!1}return!1}var p=Object.freeze(P);function $(e){let t="";for(let n=0;n<e.childNodes.length;n++){let o=e.childNodes[n];o.nodeType===Node.TEXT_NODE&&(t+=o.textContent)}return t.trim()}function ce(e){if(e.tagName==="STYLE"||e.tagName==="SCRIPT"||e.querySelector("STYLE, SCRIPT"))return!0;let t=e.parentElement;for(;t;){if(t.tagName==="STYLE"||t.tagName==="SCRIPT")return!0;t=t.parentElement}return!1}function F(e){let t=e.getAttribute("aria-labelledby");if(!t)return"";let n=t.split(/\s+/),o="";for(let r of n)try{let i=document.getElementById(r);i&&(o+=i.textContent)}catch(i){}return o}function S(e,t,n=!1){if(e==null)return!1;if(t==null||t==="")return!0;if(ce(e))return!1;let o=E;for(let l=0;l<o.length;l++){let s=o[l],a;try{a=e.getAttribute(s)}catch(f){continue}if(a){if(s==="aria-labelledby"){if(n?a===t:a.includes(t))return!0;let f=F(e);if(f&&(n?f===t:f.includes(t)))return!0}else if(n?a===t:a.includes(t))return!0}}let r=$(e);if(n?r===t:r.includes(t))return!0;let i=e.textContent;return!!(n?i.trim()===t:i.includes(t))}function g(e,t){if(e==null)return!1;let n=C.get(t);return n?n(e):!1}function y(e=document){let t=[];if(e==null)return t;let n=e.nodeType===Node.DOCUMENT_NODE?e.documentElement:e;if(!n)return t;let o=[n];for(;o.length>0;){let r=o.pop();if(r.nodeType!==Node.ELEMENT_NODE||r.tagName==="SCRIPT"||r.tagName==="STYLE")continue;t.push(r);let i=r.children;for(let l=i.length-1;l>=0;l--)o.push(i[l]);try{if(r.shadowRoot){let l=r.shadowRoot.children;for(let s=l.length-1;s>=0;s--)o.push(l[s])}}catch(l){}}return t}function x(e=window){let t=[];try{t.push({window:e,document:e.document,isMainFrame:!0,frameIndex:-1});let n=e.document.querySelectorAll("iframe");for(let o=0;o<n.length;o++){let r=n[o];try{r.contentWindow&&r.contentDocument&&t.push({window:r.contentWindow,document:r.contentDocument,isMainFrame:!1,frameElement:r,frameIndex:o})}catch(i){i.name==="SecurityError"?console.warn("Skipping cross-origin iframe:",i.message):console.warn("Error accessing iframe:",i.message)}}}catch(n){console.warn("Error getting frames:",n.message)}return t}function A(e){let t=e.getBoundingClientRect();return{x:t.x,y:t.y,width:t.width,height:t.height,top:t.top,bottom:t.bottom,left:t.left,right:t.right,midx:t.x+t.width/2,midy:t.y+t.height/2,tagName:e.tagName.toLowerCase()}}function N(e){if(e==null)return!0;let t=e;for(;t;){if(ue(t))return!0;t=t.parentElement}return!1}function ue(e){if(e.hasAttribute("hidden")||e.getAttribute("aria-hidden")==="true"||e.inert||e.offsetWidth===0&&e.offsetHeight===0)return!0;if(typeof e.checkVisibility=="function")return!e.checkVisibility({checkOpacity:!0,checkVisibilityCSS:!0,contentVisibilityAuto:!0});try{let t=window.getComputedStyle(e);if(t.visibility==="hidden"||t.visibility==="collapse"||t.display==="none"||t.opacity==="0")return!0}catch(t){}return!1}function z(e="element",t=null,n=null){if(e==null&&(e="element"),typeof e!="string")throw new TypeError(`type must be a string, got ${typeof e}`);let o=n&&n.failOnUnknownType===!0;if(e&&!p[e]){let a=`Unknown element type: ${e}. Valid types: ${Object.keys(p).join(", ")}`;if(o)throw new TypeError(`Unknown element type: ${e}`);return console.warn(a),{elements:[]}}let r=[],i=x(window);for(let a of i){let f=y(t||a.document);for(let u=0;u<f.length;u++){let c=f[u];e&&!g(c,e)||r.push({element:c,frame:a})}}let l=[];if(r.length>0){let a=new Set(r.map(u=>u.element)),f=new Set;for(let u=r.length-1;u>=0;u--){let c=r[u],d=c.element;if(!f.has(d)){l.unshift(c);let m=d.parentElement;for(;m;)a.has(m)&&f.add(m),m=m.parentElement}}}return{elements:l.map(a=>{let f=A(a.element),u=a.element.tagName.toLowerCase(),c=N(a.element);return a.frame.isMainFrame?{element:a.element,boundingBox:f,tagName:u,frameIndex:a.frame.frameIndex,isHidden:c}:{boundingBox:f,tagName:u,frameIndex:a.frame.frameIndex,isHidden:c}})}}function W(e,t=!1,n=null){if(e==null&&(e=""),typeof e!="string")throw new TypeError(`value must be a string, got ${typeof e}`);let o=[],r=x(window);for(let s of r){let a=y(n||s.document);for(let f=0;f<a.length;f++){let u=a[f];S(u,e,t)&&o.push({element:u,frame:s})}}return{elements:o.filter(s=>{let a=s.element;if(k(a,e,t))return!0;for(let u of o)if(u.element!==a&&a.contains(u.element))return!1;return!0}).map(s=>{let a=A(s.element),f=s.element.tagName.toLowerCase(),u=N(s.element);return s.frame.isMainFrame?{element:s.element,boundingBox:a,tagName:f,frameIndex:s.frame.frameIndex,isHidden:u}:{boundingBox:a,tagName:f,frameIndex:s.frame.frameIndex,isHidden:u}})}}function k(e,t,n=!1){if(t==null||t==="")return!0;let o=E;for(let i=0;i<o.length;i++){let l=o[i],s;try{s=e.getAttribute(l)}catch(a){continue}if(s){if(l==="aria-labelledby"){if(n?s===t:s.includes(t))return!0;let a=F(e);if(a&&(n?a===t:a.includes(t)))return!0}else if(n?s===t:s.includes(t))return!0}}let r=$(e);return!!(n?r===t:r.includes(t))}function de(e=null,t=null,n=null){let o=e!=null;if(o){if(typeof e!="string")throw new TypeError(`type must be a string, got ${typeof e}`);if(!p[e]){let s=`Unknown element type: ${e}. Valid types: ${Object.keys(p).join(", ")}`;if(n&&n.failOnUnknownType===!0)throw new TypeError(`Unknown element type: ${e}`);return console.warn(s),{[e]:{visible:0,hidden:0,total:0}}}}let r={},i=o?[e]:Object.keys(p).filter(s=>s!=="element");for(let s=0;s<i.length;s++)r[i[s]]={visible:0,hidden:0,total:0};let l=x(window);for(let s=0;s<l.length;s++){let a=l[s],f=y(t||a.document);for(let u=0;u<f.length;u++){let c=f[u];for(let d=0;d<i.length;d++){let m=i[d];if(g(c,m)){let h=N(c)?"hidden":"visible";r[m][h]+=1,r[m].total+=1}}}}return r}function me(e=null,t=null,n=!1,o=null,r=null){if(t==null&&(t=""),e!=null){if(typeof e!="string")throw new TypeError(`type must be a string, got ${typeof e}`);if(!p[e]){let f=`Unknown element type: ${e}. Valid types: ${Object.keys(p).join(", ")}`;if(r&&r.failOnUnknownType===!0)throw new TypeError(`Unknown element type: ${e}`);return console.warn(f),{elements:[]}}}if(t!==""&&typeof t!="string")throw new TypeError(`text must be a string, got ${typeof t}`);let i=[],l=x(window);for(let f of l){let u=y(o||f.document);for(let c=0;c<u.length;c++){let d=u[c];e!=null&&!g(d,e)||t!==""&&!S(d,t,n)||i.push({element:d,frame:f})}}return{elements:(t!==""?i.filter(f=>{let u=f.element;if(k(u,t,n))return!0;for(let d of i)if(d.element!==u&&u.contains(d.element))return!1;return!0}):i).map(f=>{let u=A(f.element),c=f.element.tagName.toLowerCase(),d=N(f.element);return f.frame.isMainFrame?{element:f.element,boundingBox:u,tagName:c,frameIndex:f.frame.frameIndex,isHidden:d}:{boundingBox:u,tagName:c,frameIndex:f.frame.frameIndex,isHidden:d}})}}function L(e){if(e.parentElement)return e.parentElement;try{let t=e.getRootNode();if(t&&t.host)return t.host}catch(t){}return null}function q(e){let t=L(e);if(!t)return[];if(t.shadowRoot)try{return Array.from(t.shadowRoot.children)}catch(n){return[]}return Array.from(t.children)}function he(e,t){let n=L(e);for(;n;){if(g(n,t))return n;n=L(n)}let o=e.children||[];for(let l of o)if(g(l,t))return l;let r=q(e);for(let l of r)if(l!==e&&g(l,t))return l;for(let l of r){if(l===e)continue;let s=y(l);for(let a=0;a<s.length;a++)if(g(s[a],t))return s[a]}let i=e.parentElement;for(;i;){let l=q(i);for(let s of l)if(s!==i){if(g(s,t))return s;let a=y(s);for(let f=0;f<a.length;f++)if(g(a[f],t))return a[f]}i=i.parentElement}return null}function ge(e,t,n=!1,o=null,r=null){let i=e!=null&&e!=="",l=t!=null&&t!=="";if(i&&!l)return z(e,o,r);if(!i&&l)return W(t,n,o);if(i){if(typeof e!="string")throw new TypeError(`elementType must be a string, got ${typeof e}`);if(!p[e]){let c=`Unknown element type: ${e}. Valid types: ${Object.keys(p).join(", ")}`;if(r&&r.failOnUnknownType===!0)throw new TypeError(`Unknown element type: ${e}`);return console.warn(c),{elements:[]}}}if(l&&typeof t!="string")throw new TypeError(`attributeText must be a string, got ${typeof t}`);let s=[],a=x(window);for(let c of a){let d=y(o||c.document);for(let m=0;m<d.length;m++){let h=d[m];i&&!g(h,e)||l&&!S(h,t,n)||s.push({element:h,frame:c})}}if(s.length===0&&i&&l){let c=[];for(let m of a){let h=y(o||m.document);for(let O=0;O<h.length;O++){let M=h[O];S(M,t,n)&&k(M,t,n)&&c.push({element:M,frame:m})}}let d=new Set;for(let m of c){let h=he(m.element,e);h&&!d.has(h)&&(d.add(h),s.push({element:h,frame:m.frame}))}}return{elements:(l?s.filter(c=>{let d=c.element;if(k(d,t,n))return!0;for(let h of s)if(h.element!==d&&d.contains(h.element))return!1;return!0}):s).map(c=>{let d=A(c.element),m=c.element.tagName.toLowerCase(),h=N(c.element);return c.frame.isMainFrame?{element:c.element,boundingBox:d,tagName:m,frameIndex:c.frame.frameIndex,isHidden:h}:{boundingBox:d,tagName:m,frameIndex:c.frame.frameIndex,isHidden:h}})}}function X(e){return e?e&&e.elements&&Array.isArray(e.elements)?e.elements:Array.isArray(e)?e:[e]:[]}function pe(e,t="red",n=3){let o=X(e);for(let r=0;r<o.length;r++){let i=o[r],l=i.element?i.element:i;l&&l.style&&(l.style.outline=`${n}px solid ${t}`,l.style.outlineOffset="2px",l.style.boxShadow="0 0 0 2px rgba(255, 255, 255, 0.8)",l.classList.add("elementfinder-highlighted"))}}function ye(e){let t=X(e);for(let n=0;n<t.length;n++){let o=t[n],r=o.element?o.element:o;r&&r.style&&(r.style.outline="",r.style.outlineOffset="",r.style.boxShadow="",r.classList.remove("elementfinder-highlighted"))}}var T=[];function be(){let e=new Map,t=y();for(let r of t)r&&r.style&&r.style.animationPlayState!=="paused"&&(e.set(r,{animationPlayState:r.style.animationPlayState,transitionProperty:r.style.transitionProperty,webkitAnimationPlayState:r.style.webkitAnimationPlayState,webkitTransitionProperty:r.style.webkitTransitionProperty}),r.style.animationPlayState="paused",r.style.transitionProperty="none",r.style.webkitAnimationPlayState="paused",r.style.webkitTransitionProperty="none");let n=document.getElementById("elementfinder-animation-pause");n||(n=document.createElement("style"),n.id="elementfinder-animation-pause",n.textContent=`
2
2
  *, *::before, *::after {
3
3
  animation-play-state: paused !important;
4
4
  transition-property: none !important;
@@ -12,4 +12,4 @@ var ElementFinder=(()=>{var P=Object.defineProperty;var W=Object.getOwnPropertyD
12
12
  transition-duration: 0s !important;
13
13
  }
14
14
  }
15
- `,document.head.appendChild(n));let o={originalStyles:e,pausedCount:e.size};return N.push(o),o}function pe(e){if(e){let n=N.indexOf(e);if(n===-1)return;N.splice(n,1)}else{if(N.length===0)return;e=N.pop()}let t=e.originalStyles;if(t)for(let[n,o]of t)n&&n.style&&(n.style.animationPlayState=o.animationPlayState||"",n.style.transitionProperty=o.transitionProperty||"",n.style.webkitAnimationPlayState=o.webkitAnimationPlayState||"",n.style.webkitTransitionProperty=o.webkitTransitionProperty||"");if(N.length===0){let n=document.getElementById("elementfinder-animation-pause");n&&n.remove()}}function ye(){return Object.keys(p)}function be(){return[...E]}return G(we);})();
15
+ `,document.head.appendChild(n));let o={originalStyles:e,pausedCount:e.size};return T.push(o),o}function we(e){if(e){let n=T.indexOf(e);if(n===-1)return;T.splice(n,1)}else{if(T.length===0)return;e=T.pop()}let t=e.originalStyles;if(t)for(let[n,o]of t)n&&n.style&&(n.style.animationPlayState=o.animationPlayState||"",n.style.transitionProperty=o.transitionProperty||"",n.style.webkitAnimationPlayState=o.webkitAnimationPlayState||"",n.style.webkitTransitionProperty=o.webkitTransitionProperty||"");if(T.length===0){let n=document.getElementById("elementfinder-animation-pause");n&&n.remove()}}function Ee(){return Object.keys(p)}function xe(){return[...E]}return K(Te);})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nodebug/browser-element-finder",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "description": "Browser Element Finder - Find elements by type and text content",
5
5
  "exports": {
6
6
  ".": {
@@ -23,6 +23,9 @@ const REGEX_PATTERNS = {
23
23
  // Maximum recursion depth for XPath parsing to prevent stack overflow
24
24
  const MAX_RECURSION_DEPTH = 100;
25
25
 
26
+ // Maximum length for text/textContent fallback descriptors
27
+ const MAX_IDENTIFIABLE_TEXT_LENGTH = 25;
28
+
26
29
  // Pre-compiled type matcher functions for faster type checking
27
30
  const TYPE_MATCHERS = new Map();
28
31
 
@@ -99,6 +102,33 @@ function normalizeDescriptorText(text) {
99
102
  return String(text).replace(/\s+/g, ' ').trim();
100
103
  }
101
104
 
105
+ /**
106
+ * Shortens text fallback descriptors without cutting words.
107
+ * Uses only the first non-empty line so text after new lines is ignored.
108
+ * @param {string|null|undefined} text - Text to shorten
109
+ * @returns {string} Shortened normalized text
110
+ */
111
+ function shortenDescriptorText(text) {
112
+ if (text == null) return '';
113
+
114
+ const lines = String(text).split(/\r\n|\r|\n/);
115
+ let normalizedText = '';
116
+
117
+ for (let i = 0; i < lines.length; i++) {
118
+ normalizedText = normalizeDescriptorText(lines[i]);
119
+ if (normalizedText) break;
120
+ }
121
+
122
+ if (!normalizedText || normalizedText.length <= MAX_IDENTIFIABLE_TEXT_LENGTH) {
123
+ return normalizedText;
124
+ }
125
+
126
+ const shortened = normalizedText.slice(0, MAX_IDENTIFIABLE_TEXT_LENGTH);
127
+ const lastSpaceIndex = shortened.lastIndexOf(' ');
128
+
129
+ return lastSpaceIndex > 0 ? shortened.slice(0, lastSpaceIndex) : normalizedText;
130
+ }
131
+
102
132
  /**
103
133
  * Gets the filename portion of an image src without path or extension.
104
134
  * @param {string|null|undefined} src - Image src value
@@ -178,12 +208,12 @@ function getElementDescriptorText(el) {
178
208
  }
179
209
  }
180
210
 
181
- const directText = normalizeDescriptorText(getDirectText(el));
211
+ const directText = shortenDescriptorText(getDirectText(el));
182
212
  if (directText) {
183
213
  return { attributeName: 'text', identifiableText: directText };
184
214
  }
185
215
 
186
- const fullText = normalizeDescriptorText(el.textContent);
216
+ const fullText = shortenDescriptorText(el.textContent);
187
217
  if (fullText) {
188
218
  return { attributeName: 'text', identifiableText: fullText };
189
219
  }
@@ -711,36 +741,60 @@ export function getBoundingBox(el) {
711
741
 
712
742
  /**
713
743
  * Checks if an element is hidden (not visible on the page).
714
- * Considers offset dimensions, CSS visibility, display, and hidden attribute.
744
+ * Considers native visibility checks, ancestor visibility, CSS visibility/display/opacity,
745
+ * hidden/inert/aria-hidden attributes, and offset dimensions.
715
746
  * @param {Element} el - The DOM element to check
716
747
  * @returns {boolean} True if the element is hidden
717
748
  */
718
749
  export function isHidden(el) {
719
750
  if (el == null) return true;
720
751
 
721
- // Check offset dimensions (element has no size)
722
- if (el.offsetWidth === 0 && el.offsetHeight === 0) {
752
+ let parent = el;
753
+ while (parent) {
754
+ if (isElementHidden(parent)) {
755
+ return true;
756
+ }
757
+ parent = parent.parentElement;
758
+ }
759
+
760
+ return false;
761
+ }
762
+
763
+ function isElementHidden(el) {
764
+ if (
765
+ el.hasAttribute('hidden') ||
766
+ el.getAttribute('aria-hidden') === 'true' ||
767
+ el.inert ||
768
+ (el.offsetWidth === 0 && el.offsetHeight === 0)
769
+ ) {
723
770
  return true;
724
771
  }
725
772
 
726
- // Check computed styles for visibility and display
727
- try {
728
- const style = window.getComputedStyle(el);
729
- if (style.visibility === 'hidden' || style.visibility === 'collapse') {
773
+ if (typeof el.checkVisibility === 'function') {
774
+ if (!el.checkVisibility({
775
+ checkOpacity: true,
776
+ checkVisibilityCSS: true,
777
+ contentVisibilityAuto: true
778
+ })) {
730
779
  return true;
731
780
  }
732
- if (style.display === 'none') {
781
+ return false;
782
+ }
783
+
784
+ try {
785
+ const style = window.getComputedStyle(el);
786
+ if (
787
+ style.visibility === 'hidden' ||
788
+ style.visibility === 'collapse' ||
789
+ style.display === 'none' ||
790
+ style.opacity === '0'
791
+ ) {
733
792
  return true;
734
793
  }
735
794
  } catch {
736
795
  // Restricted access - continue with other checks
737
796
  }
738
797
 
739
- // Check hidden attribute
740
- if (el.hasAttribute('hidden')) {
741
- return true;
742
- }
743
-
744
798
  return false;
745
799
  }
746
800
 
@@ -962,14 +1016,14 @@ function hasOwnMatch(el, value, exact = false) {
962
1016
  }
963
1017
 
964
1018
  /**
965
- * Gets counts of elements by semantic type on the current screen.
1019
+ * Gets counts of elements by semantic type and visibility on the current screen.
966
1020
  * Excludes the generic `element` type unless a specific type is requested.
967
1021
  * If no type is provided, returns counts for all defined non-generic types.
968
1022
  * Searches all frames (main document + iframes) by default.
969
1023
  * @param {string|null|undefined} [type=null] - Element type to count. If null/undefined, count all defined non-generic types.
970
1024
  * @param {Element|null} [parent=null] - Parent element to count within
971
1025
  * @param {{failOnUnknownType?: boolean}} [options=null] - Search options
972
- * @returns {Object.<string, number>} Counts keyed by semantic element type, or `{ [type]: count }` when type is provided
1026
+ * @returns {Object.<string, {visible: number, hidden: number, total: number}>} Counts keyed by semantic element type, or `{ [type]: { visible, hidden, total } }` when type is provided
973
1027
  */
974
1028
  export function getElementCounts(type = null, parent = null, options = null) {
975
1029
  const hasType = type !== null && type !== undefined;
@@ -984,7 +1038,7 @@ export function getElementCounts(type = null, parent = null, options = null) {
984
1038
  throw new TypeError(`Unknown element type: ${type}`);
985
1039
  }
986
1040
  console.warn(message);
987
- return { [type]: 0 };
1041
+ return { [type]: { visible: 0, hidden: 0, total: 0 } };
988
1042
  }
989
1043
  }
990
1044
 
@@ -992,7 +1046,7 @@ export function getElementCounts(type = null, parent = null, options = null) {
992
1046
  const targetTypes = hasType ? [type] : Object.keys(ELEMENT_DEFINITIONS).filter((item) => item !== 'element');
993
1047
 
994
1048
  for (let i = 0; i < targetTypes.length; i++) {
995
- counts[targetTypes[i]] = 0;
1049
+ counts[targetTypes[i]] = { visible: 0, hidden: 0, total: 0 };
996
1050
  }
997
1051
 
998
1052
  const frames = getAllFrames(window);
@@ -1008,7 +1062,9 @@ export function getElementCounts(type = null, parent = null, options = null) {
1008
1062
  for (let k = 0; k < targetTypes.length; k++) {
1009
1063
  const targetType = targetTypes[k];
1010
1064
  if (matchesType(el, targetType)) {
1011
- counts[targetType] += 1;
1065
+ const bucket = isHidden(el) ? 'hidden' : 'visible';
1066
+ counts[targetType][bucket] += 1;
1067
+ counts[targetType].total += 1;
1012
1068
  }
1013
1069
  }
1014
1070
  }