@guidelytech/guide-runtime 0.9.0 → 0.10.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.cjs CHANGED
@@ -24,12 +24,19 @@ var src_exports = {};
24
24
  __export(src_exports, {
25
25
  DEFAULT_THEME: () => DEFAULT_THEME,
26
26
  HOST_ID: () => HOST_ID2,
27
+ SHADOW_SEPARATOR: () => SHADOW_SEPARATOR,
27
28
  STYLES: () => STYLES,
28
29
  TargetTimeoutError: () => TargetTimeoutError,
29
30
  anchor: () => anchor,
30
31
  applyTheme: () => applyTheme,
31
32
  buildCard: () => buildCard,
33
+ closestComposed: () => closestComposed,
34
+ componentAnchor: () => componentAnchor,
35
+ composedParent: () => composedParent,
36
+ composedTarget: () => composedTarget,
37
+ containsComposed: () => containsComposed,
32
38
  createScope: () => createScope,
39
+ deepElementFromPoint: () => deepElementFromPoint,
33
40
  describeElement: () => describeElement,
34
41
  destroyHost: () => destroyHost,
35
42
  enhancePdfViewers: () => enhancePdfViewers,
@@ -63,10 +70,12 @@ __export(src_exports, {
63
70
  sanitizeHtml: () => sanitizeHtml,
64
71
  sanitizeToFragment: () => sanitizeToFragment,
65
72
  setSanitizedHtml: () => setSanitizedHtml,
73
+ shadowHostChain: () => shadowHostChain,
66
74
  startAuthoring: () => startAuthoring,
67
75
  textSnapshotOf: () => textSnapshotOf,
68
76
  trackRect: () => trackRect,
69
77
  urlMatches: () => urlMatches,
78
+ visualRect: () => visualRect,
70
79
  waitForTarget: () => waitForTarget
71
80
  });
72
81
  module.exports = __toCommonJS(src_exports);
@@ -129,6 +138,82 @@ function safeQueryAll(root, selector) {
129
138
  return [];
130
139
  }
131
140
  }
141
+ var SHADOW_SEPARATOR = " >>> ";
142
+ var SHADOW_SPLIT = /\s*>>>\s*/;
143
+ function isShadowRoot(node) {
144
+ return !!node && node.nodeType === 11 && !!node.host;
145
+ }
146
+ function shadowRootOf(el2) {
147
+ const root = el2.getRootNode?.();
148
+ return isShadowRoot(root) ? root : null;
149
+ }
150
+ function composedParent(el2) {
151
+ return el2.parentElement ?? shadowRootOf(el2)?.host ?? null;
152
+ }
153
+ function containsComposed(ancestor, node) {
154
+ let cur = node ? node.nodeType === 1 ? node : node.parentElement : null;
155
+ for (; cur; cur = composedParent(cur)) if (cur === ancestor) return true;
156
+ return false;
157
+ }
158
+ function composedTarget(e) {
159
+ const path = typeof e.composedPath === "function" ? e.composedPath() : [];
160
+ const first = path[0] ?? e.target;
161
+ if (!first) return null;
162
+ return first.nodeType === 1 ? first : first.parentElement;
163
+ }
164
+ var shadowRootCache = null;
165
+ function shadowRootsIn(root) {
166
+ const cached = shadowRootCache?.get(root);
167
+ if (cached) return cached;
168
+ const out = [];
169
+ const visit = (scope) => {
170
+ const own = scope.nodeType === 1 ? scope.shadowRoot : null;
171
+ const hosts = own ? [scope] : [];
172
+ for (const el2 of safeQueryAll(scope, "*")) if (el2.shadowRoot) hosts.push(el2);
173
+ for (const host of hosts) {
174
+ if (host.id === HOST_ID || !host.shadowRoot || out.includes(host.shadowRoot)) continue;
175
+ out.push(host.shadowRoot);
176
+ visit(host.shadowRoot);
177
+ }
178
+ };
179
+ visit(root);
180
+ shadowRootCache?.set(root, out);
181
+ return out;
182
+ }
183
+ function queryAllDeep(root, selector) {
184
+ const out = safeQueryAll(root, selector);
185
+ for (const sr of shadowRootsIn(root)) out.push(...safeQueryAll(sr, selector));
186
+ return out;
187
+ }
188
+ function queryCss(root, selector, deep) {
189
+ if (!selector.includes(">>>")) return deep ? queryAllDeep(root, selector) : safeQueryAll(root, selector);
190
+ const steps = selector.split(SHADOW_SPLIT).filter(Boolean);
191
+ let scopes = [root];
192
+ let matches = [];
193
+ steps.forEach((step, i) => {
194
+ matches = Array.from(new Set(scopes.flatMap((scope) => queryAllDeep(scope, step))));
195
+ if (i < steps.length - 1) scopes = matches.map((el2) => el2.shadowRoot).filter((sr) => !!sr);
196
+ });
197
+ return matches;
198
+ }
199
+ function closestComposed(el2, selector) {
200
+ if (selector.includes(">>>")) {
201
+ const hits = new Set(queryCss(docOf(el2), selector, true));
202
+ for (let cur = el2; cur; cur = composedParent(cur)) if (hits.has(cur)) return cur;
203
+ return null;
204
+ }
205
+ for (let cur = el2; cur; cur = composedParent(cur)) if (cur.matches(selector)) return cur;
206
+ return null;
207
+ }
208
+ function deepElementFromPoint(doc, x, y) {
209
+ let el2 = doc.elementFromPoint(x, y);
210
+ while (el2?.shadowRoot && el2.id !== HOST_ID && typeof el2.shadowRoot.elementFromPoint === "function") {
211
+ const inner = el2.shadowRoot.elementFromPoint(x, y);
212
+ if (!inner || inner === el2) break;
213
+ el2 = inner;
214
+ }
215
+ return el2;
216
+ }
132
217
  function escapeCss(value) {
133
218
  const g = globalThis;
134
219
  if (g.CSS && typeof g.CSS.escape === "function") return g.CSS.escape(value);
@@ -150,32 +235,32 @@ function queryXPath(root, expr) {
150
235
  return [];
151
236
  }
152
237
  }
153
- function queryText(root, text) {
238
+ function queryText(root, text, deep) {
154
239
  const needle = normalizeText(text).toLowerCase();
155
240
  if (!needle) return [];
156
- const candidates = safeQueryAll(root, TEXT_CANDIDATES);
241
+ const candidates = queryCss(root, TEXT_CANDIDATES, deep);
157
242
  const exact = candidates.filter((c) => normalizeText(c.textContent).toLowerCase() === needle);
158
243
  if (exact.length) return exact;
159
244
  return candidates.filter((c) => normalizeText(c.textContent).toLowerCase().includes(needle));
160
245
  }
161
- function querySelectorStrategy(strategy, root) {
246
+ function querySelectorStrategy(strategy, root, deep = true) {
162
247
  const value = strategy.value.trim();
163
248
  if (!value) return [];
164
249
  switch (strategy.kind) {
165
250
  case "id": {
166
251
  const id = value.startsWith("#") ? value.slice(1) : value;
167
- return safeQueryAll(root, `#${escapeCss(id)}`);
252
+ return queryCss(root, `#${escapeCss(id)}`, deep);
168
253
  }
169
254
  case "guidely-id": {
170
255
  const id = value.startsWith("#") ? value.slice(1) : value;
171
- return safeQueryAll(root, attrSelector("data-guidely-id", id));
256
+ return queryCss(root, attrSelector("data-guidely-id", id), deep);
172
257
  }
173
258
  case "data-attr":
174
259
  case "aria":
175
260
  case "css":
176
- return safeQueryAll(root, value.startsWith("[") || /^[a-z*#.[]/i.test(value) ? value : `[${value}]`);
261
+ return queryCss(root, value.startsWith("[") || /^[a-z*#.[]/i.test(value) ? value : `[${value}]`, deep);
177
262
  case "text":
178
- return queryText(root, value);
263
+ return queryText(root, value, deep);
179
264
  case "xpath":
180
265
  return queryXPath(root, value);
181
266
  default:
@@ -184,11 +269,19 @@ function querySelectorStrategy(strategy, root) {
184
269
  }
185
270
  function resolveTarget(target, root = document) {
186
271
  const selectors = Array.isArray(target) ? target : target.selectors;
187
- for (const strategy of selectors) {
188
- const matches = querySelectorStrategy(strategy, root).filter((el2) => !isGuidelyElement(el2) && isVisible(el2));
189
- if (matches.length === 1) return matches[0];
272
+ const visibleMatches = (strategy, deep) => querySelectorStrategy(strategy, root, deep).filter((el2) => !isGuidelyElement(el2) && isVisible(el2));
273
+ const outer = shadowRootCache;
274
+ shadowRootCache ?? (shadowRootCache = /* @__PURE__ */ new Map());
275
+ try {
276
+ for (const strategy of selectors) {
277
+ let matches = visibleMatches(strategy, false);
278
+ if (!matches.length && strategy.kind !== "xpath") matches = visibleMatches(strategy, true);
279
+ if (matches.length === 1) return matches[0];
280
+ }
281
+ return null;
282
+ } finally {
283
+ shadowRootCache = outer;
190
284
  }
191
- return null;
192
285
  }
193
286
  var TargetTimeoutError = class extends Error {
194
287
  constructor(message = "Target element not found before timeout") {
@@ -252,14 +345,15 @@ function isStableId(id) {
252
345
  function isStableClass(cls) {
253
346
  return !!cls && !GENERATED_CLASS.test(cls) && cls.length <= 40;
254
347
  }
255
- function uniqueIn(doc, selector, el2) {
256
- const all = safeQueryAll(doc, selector);
348
+ function uniqueWithin(root, selector, el2) {
349
+ const all = safeQueryAll(root, selector);
257
350
  return all.length === 1 && all[0] === el2;
258
351
  }
259
352
  function attrSelector(name, value) {
260
353
  return `[${name}='${value.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}']`;
261
354
  }
262
- function cssPath(el2, doc) {
355
+ function cssPath(el2, root) {
356
+ const doc = el2.ownerDocument;
263
357
  const segments = [];
264
358
  let cur = el2;
265
359
  while (cur && cur.nodeType === 1 && cur !== doc.body && cur !== doc.documentElement) {
@@ -279,20 +373,48 @@ function cssPath(el2, doc) {
279
373
  }
280
374
  segments.unshift(seg);
281
375
  const candidate = segments.join(" > ");
282
- if (uniqueIn(doc, candidate, el2)) return candidate;
376
+ if (uniqueWithin(root, candidate, el2)) return candidate;
283
377
  cur = parent;
284
378
  }
285
379
  const full = segments.join(" > ");
286
- return uniqueIn(doc, full, el2) ? full : null;
380
+ return uniqueWithin(root, full, el2) ? full : null;
381
+ }
382
+ function shadowHostChain(el2) {
383
+ const steps = [];
384
+ for (let root = shadowRootOf(el2); root; root = shadowRootOf(root.host)) {
385
+ const host = root.host;
386
+ const step = cssPath(host, shadowRootOf(host) ?? host.ownerDocument);
387
+ if (!step) return null;
388
+ steps.unshift(step);
389
+ }
390
+ return steps.join(SHADOW_SEPARATOR);
391
+ }
392
+ function selectorFor(el2, selector) {
393
+ const root = shadowRootOf(el2);
394
+ if (!root) return uniqueWithin(el2.ownerDocument, selector, el2) ? selector : null;
395
+ if (!uniqueWithin(root, selector, el2)) return null;
396
+ const doc = el2.ownerDocument;
397
+ const only = (sel) => {
398
+ const all = queryCss(doc, sel, true);
399
+ return all.length === 1 && all[0] === el2;
400
+ };
401
+ if (only(selector)) return selector;
402
+ const chain = shadowHostChain(el2);
403
+ const scoped = chain ? chain + SHADOW_SEPARATOR + selector : null;
404
+ return scoped && only(scoped) ? scoped : null;
405
+ }
406
+ function shadowText(el2) {
407
+ if (!el2.shadowRoot) return "";
408
+ const parts = Array.from(el2.shadowRoot.children).filter((c) => !/^(STYLE|SCRIPT|TEMPLATE)$/.test(c.tagName));
409
+ return normalizeText(parts.map((c) => c.innerText ?? c.textContent).join(" "));
287
410
  }
288
411
  function textSnapshotOf(el2) {
289
412
  const he = el2;
290
- const own = normalizeText(he.innerText ?? el2.textContent);
413
+ const own = normalizeText(he.innerText ?? el2.textContent) || shadowText(el2);
291
414
  const alt = normalizeText(el2.getAttribute("aria-label") || el2.getAttribute("title") || el2.getAttribute("placeholder") || el2.getAttribute("alt") || el2.value);
292
415
  return (own || alt).slice(0, 200);
293
416
  }
294
417
  function generateSelectors(el2) {
295
- const doc = el2.ownerDocument;
296
418
  const out = [];
297
419
  const seen = /* @__PURE__ */ new Set();
298
420
  const push = (s) => {
@@ -303,9 +425,15 @@ function generateSelectors(el2) {
303
425
  }
304
426
  };
305
427
  const tag = el2.tagName.toLowerCase();
428
+ const pushFor = (kind, selector, value, label) => {
429
+ const resolved = selectorFor(el2, selector);
430
+ if (resolved === selector) push({ kind, value, label });
431
+ else if (resolved) push({ kind: "css", value: resolved, label });
432
+ return !!resolved;
433
+ };
306
434
  const guidelyId = el2.getAttribute("data-guidely-id");
307
- if (guidelyId && uniqueIn(doc, attrSelector("data-guidely-id", guidelyId), el2)) push({ kind: "guidely-id", value: guidelyId, label: `Guidely id ${guidelyId}` });
308
- if (isStableId(el2.id) && uniqueIn(doc, `#${escapeCss(el2.id)}`, el2)) push({ kind: "id", value: `#${el2.id}`, label: `id ${el2.id}` });
435
+ if (guidelyId) pushFor("guidely-id", attrSelector("data-guidely-id", guidelyId), guidelyId, `Guidely id ${guidelyId}`);
436
+ if (isStableId(el2.id)) pushFor("id", `#${escapeCss(el2.id)}`, `#${el2.id}`, `id ${el2.id}`);
309
437
  const dataAttrs = Array.from(el2.attributes).filter((a) => a.name.startsWith("data-") && !IGNORED_DATA_ATTRS.test(a.name) && a.value && a.value.length <= 120 && !/\d{5,}/.test(a.value));
310
438
  dataAttrs.sort((a, b) => {
311
439
  const ia = PREFERRED_DATA_ATTRS.indexOf(a.name);
@@ -314,42 +442,75 @@ function generateSelectors(el2) {
314
442
  });
315
443
  for (const a of dataAttrs) {
316
444
  const sel = attrSelector(a.name, a.value);
317
- if (uniqueIn(doc, sel, el2)) push({ kind: "data-attr", value: sel, label: `${a.name}=${a.value}` });
318
- else if (uniqueIn(doc, tag + sel, el2)) push({ kind: "data-attr", value: tag + sel, label: `${a.name}=${a.value}` });
445
+ if (!pushFor("data-attr", sel, sel, `${a.name}=${a.value}`)) pushFor("data-attr", tag + sel, tag + sel, `${a.name}=${a.value}`);
319
446
  }
320
447
  const aria = el2.getAttribute("aria-label");
321
448
  if (aria && aria.length <= 120) {
322
449
  const sel = attrSelector("aria-label", aria);
323
- if (uniqueIn(doc, sel, el2)) push({ kind: "aria", value: sel, label: aria });
324
- else if (uniqueIn(doc, tag + sel, el2)) push({ kind: "aria", value: tag + sel, label: aria });
450
+ if (!pushFor("aria", sel, sel, aria)) pushFor("aria", tag + sel, tag + sel, aria);
325
451
  }
326
452
  const name = el2.getAttribute("name");
327
- if (name && uniqueIn(doc, tag + attrSelector("name", name), el2)) push({ kind: "css", value: tag + attrSelector("name", name), label: `${tag} name=${name}` });
453
+ if (name) pushFor("css", tag + attrSelector("name", name), tag + attrSelector("name", name), `${tag} name=${name}`);
328
454
  const role = el2.getAttribute("role");
329
455
  if (role) {
330
456
  const title = el2.getAttribute("title") || el2.getAttribute("aria-labelledby");
331
457
  const sel = title ? `[role='${role}']${attrSelector(el2.getAttribute("title") ? "title" : "aria-labelledby", title)}` : `[role='${role}']`;
332
- if (uniqueIn(doc, sel, el2)) push({ kind: "css", value: sel, label: `role ${role}` });
458
+ pushFor("css", sel, sel, `role ${role}`);
333
459
  }
334
460
  if (tag === "a") {
335
461
  const href = el2.getAttribute("href");
336
- if (href && href.length <= 200 && uniqueIn(doc, `a${attrSelector("href", href)}`, el2)) push({ kind: "css", value: `a${attrSelector("href", href)}`, label: `link ${href}` });
462
+ if (href && href.length <= 200) pushFor("css", `a${attrSelector("href", href)}`, `a${attrSelector("href", href)}`, `link ${href}`);
337
463
  }
338
- const path = cssPath(el2, doc);
339
- if (path) push({ kind: "css", value: path, label: "css path" });
464
+ const path = cssPath(el2, shadowRootOf(el2) ?? el2.ownerDocument);
465
+ if (path) pushFor("css", path, path, "css path");
340
466
  if (/^(button|a|h[1-6]|label|summary)$/.test(tag) || role === "button" || role === "link" || role === "tab" || role === "menuitem") {
341
467
  const text = normalizeText(el2.innerText ?? el2.textContent);
342
468
  if (text && text.length <= 80) push({ kind: "text", value: text, label: `text "${text}"` });
343
469
  }
344
470
  return out.slice(0, 10);
345
471
  }
472
+ function visualRect(el2) {
473
+ const own = el2.getBoundingClientRect();
474
+ if (!el2.shadowRoot) return own;
475
+ const boxes = [own, ...Array.from(el2.shadowRoot.children).map((c) => c.getBoundingClientRect())].filter((r) => r.width > 0 && r.height > 0);
476
+ if (boxes.length < 2) return boxes[0] ?? own;
477
+ const left = Math.min(...boxes.map((r) => r.left));
478
+ const top = Math.min(...boxes.map((r) => r.top));
479
+ const right = Math.max(...boxes.map((r) => r.right));
480
+ const bottom = Math.max(...boxes.map((r) => r.bottom));
481
+ return new DOMRect(left, top, right - left, bottom - top);
482
+ }
483
+ var ANCHOR_MAX_AREA_RATIO = 4;
484
+ var CONTROL_SELECTOR = "button, a[href], input, select, textarea, [role='button'], [role='link'], [role='checkbox'], [role='radio'], [role='switch'], [role='tab'], [role='menuitem'], [role='combobox'], [role='option']";
485
+ function componentAnchor(el2) {
486
+ if (!hasLayout(el2.ownerDocument)) return el2;
487
+ let cur = el2;
488
+ for (let root = shadowRootOf(cur); root; root = shadowRootOf(cur)) {
489
+ const host = root.host;
490
+ if (host.id === HOST_ID) break;
491
+ let control = null;
492
+ try {
493
+ control = cur.closest(CONTROL_SELECTOR);
494
+ } catch {
495
+ }
496
+ const r = visualRect(control ?? cur);
497
+ const area = r.width * r.height;
498
+ const h2 = visualRect(host);
499
+ const hostArea = h2.width * h2.height;
500
+ const inside = r.left >= h2.left - 1 && r.top >= h2.top - 1 && r.right <= h2.right + 1 && r.bottom <= h2.bottom + 1;
501
+ if (!area || !inside || hostArea > area * ANCHOR_MAX_AREA_RATIO) break;
502
+ cur = host;
503
+ }
504
+ return cur;
505
+ }
346
506
  function describeElement(el2) {
347
- const r = el2.getBoundingClientRect();
507
+ const target = componentAnchor(el2);
508
+ const r = visualRect(target);
348
509
  return {
349
- selectors: generateSelectors(el2),
350
- textSnapshot: textSnapshotOf(el2),
510
+ selectors: generateSelectors(target),
511
+ textSnapshot: textSnapshotOf(target) || textSnapshotOf(el2),
351
512
  rect: { x: r.x, y: r.y, width: r.width, height: r.height },
352
- tag: el2.tagName.toLowerCase()
513
+ tag: target.tagName.toLowerCase()
353
514
  };
354
515
  }
355
516
 
@@ -904,7 +1065,8 @@ function openReader(doc, block, link, pages, start) {
904
1065
 
905
1066
  // src/position.ts
906
1067
  var import_dom = require("@floating-ui/dom");
907
- function anchor(reference, floating, options = {}) {
1068
+ function anchor(target, floating, options = {}) {
1069
+ const reference = target.shadowRoot ? { getBoundingClientRect: () => visualRect(target), contextElement: target } : target;
908
1070
  const placement = options.placement ?? "auto";
909
1071
  const gap = options.offset ?? 10;
910
1072
  const middleware = [(0, import_dom.offset)(gap + (options.arrowEl ? 4 : 0))];
@@ -957,7 +1119,7 @@ function trackRect(el2, cb) {
957
1119
  let stopped = false;
958
1120
  const run = () => {
959
1121
  if (stopped) return;
960
- cb(el2.getBoundingClientRect());
1122
+ cb(visualRect(el2));
961
1123
  };
962
1124
  const schedule = () => {
963
1125
  if (stopped) return;
@@ -970,6 +1132,9 @@ function trackRect(el2, cb) {
970
1132
  const win = el2.ownerDocument.defaultView;
971
1133
  win?.addEventListener("scroll", schedule, true);
972
1134
  win?.addEventListener("resize", schedule);
1135
+ const shadowRoots = [];
1136
+ for (let root = el2.getRootNode(); root.nodeType === 11 && root.host; root = root.host.getRootNode()) shadowRoots.push(root);
1137
+ for (const root of shadowRoots) root.addEventListener("scroll", schedule, true);
973
1138
  let ro = null;
974
1139
  if (typeof ResizeObserver !== "undefined") {
975
1140
  try {
@@ -985,6 +1150,7 @@ function trackRect(el2, cb) {
985
1150
  stopped = true;
986
1151
  win?.removeEventListener("scroll", schedule, true);
987
1152
  win?.removeEventListener("resize", schedule);
1153
+ for (const root of shadowRoots) root.removeEventListener("scroll", schedule, true);
988
1154
  ro?.disconnect();
989
1155
  clearInterval(interval);
990
1156
  if (typeof cancelAnimationFrame === "function") cancelAnimationFrame(raf);
@@ -1532,9 +1698,9 @@ function runGuide(guide, options = {}) {
1532
1698
  if (mode === "element_click" && (step.advanceValue || target)) {
1533
1699
  const selector = step.advanceValue;
1534
1700
  const handler = (e) => {
1535
- const t = e.target;
1701
+ const t = composedTarget(e);
1536
1702
  try {
1537
- if (selector ? t && typeof t.closest === "function" && t.closest(selector) : t && target?.contains(t)) advance();
1703
+ if (selector ? t && closestComposed(t, selector) : t && target && containsComposed(target, t)) advance();
1538
1704
  } catch {
1539
1705
  }
1540
1706
  };
@@ -2565,7 +2731,7 @@ function startAuthoring(options) {
2565
2731
  outline.hidden = true;
2566
2732
  return;
2567
2733
  }
2568
- const r = el2.getBoundingClientRect();
2734
+ const r = visualRect(el2);
2569
2735
  outline.hidden = false;
2570
2736
  outline.classList.toggle("g-picked", picked);
2571
2737
  Object.assign(outline.style, { left: `${r.left}px`, top: `${r.top}px`, width: `${r.width}px`, height: `${r.height}px` });
@@ -2573,9 +2739,9 @@ function startAuthoring(options) {
2573
2739
  label.style.top = r.top < 30 ? "100%" : "-24px";
2574
2740
  };
2575
2741
  const elementAt = (x, y) => {
2576
- const el2 = doc.elementFromPoint(x, y);
2742
+ const el2 = deepElementFromPoint(doc, x, y);
2577
2743
  if (!el2 || isGuidelyElement(el2) || el2 === doc.documentElement || el2 === doc.body) return null;
2578
- return el2;
2744
+ return componentAnchor(el2);
2579
2745
  };
2580
2746
  const onMove = (e) => {
2581
2747
  if (!picking || stopped) return;
@@ -2590,7 +2756,7 @@ function startAuthoring(options) {
2590
2756
  };
2591
2757
  const onClick = (e) => {
2592
2758
  if (!picking || stopped) return;
2593
- if (e.target && isGuidelyElement(e.target)) return;
2759
+ if (isGuidelyElement(composedTarget(e))) return;
2594
2760
  const el2 = elementAt(e.clientX, e.clientY) ?? hovered;
2595
2761
  if (!el2) return;
2596
2762
  e.preventDefault();
@@ -2603,8 +2769,7 @@ function startAuthoring(options) {
2603
2769
  };
2604
2770
  const swallow = (e) => {
2605
2771
  if (!picking || stopped) return;
2606
- const t = e.target;
2607
- if (t && isGuidelyElement(t)) return;
2772
+ if (isGuidelyElement(composedTarget(e))) return;
2608
2773
  e.preventDefault();
2609
2774
  e.stopPropagation();
2610
2775
  };
@@ -2675,17 +2840,15 @@ function highlightSelectors(selectors, options = {}) {
2675
2840
  const scope = createScope(null, { theme: "light", animation: "none" }, doc);
2676
2841
  const boxes = [];
2677
2842
  const counts = [];
2678
- let resolved = null;
2843
+ const resolved = resolveTarget(selectors, doc);
2679
2844
  const matched = /* @__PURE__ */ new Set();
2680
2845
  selectors.forEach((s) => {
2681
2846
  const els = querySelectorStrategy(s, doc).filter((el2) => !isGuidelyElement(el2));
2682
- const visible = els.filter(isVisible);
2683
2847
  counts.push(els.length);
2684
- if (!resolved && visible.length === 1) resolved = visible[0];
2685
2848
  els.forEach((el2) => matched.add(el2));
2686
2849
  });
2687
2850
  matched.forEach((el2) => {
2688
- const r = el2.getBoundingClientRect();
2851
+ const r = visualRect(el2);
2689
2852
  const box = doc.createElement("div");
2690
2853
  box.className = "g-highlight";
2691
2854
  Object.assign(box.style, { left: `${r.left}px`, top: `${r.top}px`, width: `${r.width}px`, height: `${r.height}px` });
@@ -2706,12 +2869,19 @@ function highlightSelectors(selectors, options = {}) {
2706
2869
  0 && (module.exports = {
2707
2870
  DEFAULT_THEME,
2708
2871
  HOST_ID,
2872
+ SHADOW_SEPARATOR,
2709
2873
  STYLES,
2710
2874
  TargetTimeoutError,
2711
2875
  anchor,
2712
2876
  applyTheme,
2713
2877
  buildCard,
2878
+ closestComposed,
2879
+ componentAnchor,
2880
+ composedParent,
2881
+ composedTarget,
2882
+ containsComposed,
2714
2883
  createScope,
2884
+ deepElementFromPoint,
2715
2885
  describeElement,
2716
2886
  destroyHost,
2717
2887
  enhancePdfViewers,
@@ -2745,10 +2915,12 @@ function highlightSelectors(selectors, options = {}) {
2745
2915
  sanitizeHtml,
2746
2916
  sanitizeToFragment,
2747
2917
  setSanitizedHtml,
2918
+ shadowHostChain,
2748
2919
  startAuthoring,
2749
2920
  textSnapshotOf,
2750
2921
  trackRect,
2751
2922
  urlMatches,
2923
+ visualRect,
2752
2924
  waitForTarget
2753
2925
  });
2754
2926
  //# sourceMappingURL=index.cjs.map