@hereorcode/dom-inspector 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,735 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
+
5
+ // src/overlay.ts
6
+ var DEFAULT_BORDER_COLOR = "#7c3aed";
7
+ var DEFAULT_BACKGROUND_COLOR = "rgba(124, 58, 237, 0.12)";
8
+ var DEFAULT_Z_INDEX = 2147483647;
9
+ var ElementHighlighter = class {
10
+ constructor(document2, options = {}) {
11
+ __publicField(this, "document", document2);
12
+ __publicField(this, "element");
13
+ this.element = document2.createElement("dom-inspector-overlay");
14
+ this.element.setAttribute("data-dom-inspector-overlay", "true");
15
+ this.element.style.cssText = [
16
+ "position: fixed",
17
+ "top: 0",
18
+ "left: 0",
19
+ "display: none",
20
+ "pointer-events: none",
21
+ "box-sizing: border-box",
22
+ `border: 1px dashed ${options.borderColor ?? DEFAULT_BORDER_COLOR}`,
23
+ `background: ${options.backgroundColor ?? DEFAULT_BACKGROUND_COLOR}`,
24
+ `border-radius: ${options.borderRadius ?? 0}px`,
25
+ `z-index: ${options.zIndex ?? DEFAULT_Z_INDEX}`,
26
+ "transition: transform 80ms ease, width 80ms ease, height 80ms ease"
27
+ ].join(";");
28
+ const parent = document2.body ?? document2.documentElement;
29
+ parent.appendChild(this.element);
30
+ }
31
+ show(target) {
32
+ this.showRect(target.getBoundingClientRect());
33
+ }
34
+ showRect(rect) {
35
+ this.element.style.display = "block";
36
+ this.element.style.transform = `translate(${rect.left}px, ${rect.top}px)`;
37
+ this.element.style.width = `${rect.width}px`;
38
+ this.element.style.height = `${rect.height}px`;
39
+ }
40
+ hide() {
41
+ this.element.style.display = "none";
42
+ }
43
+ destroy() {
44
+ this.element.remove();
45
+ }
46
+ };
47
+
48
+ // src/path.ts
49
+ var ROOT_TAGS = /* @__PURE__ */ new Set(["html", "body"]);
50
+ function getCssSelector(element) {
51
+ const segments = [];
52
+ let current = element;
53
+ while (current && current.nodeType === 1) {
54
+ const tagName = getTagName(current);
55
+ segments.unshift(getCssSegment(current));
56
+ if (ROOT_TAGS.has(tagName)) {
57
+ break;
58
+ }
59
+ current = current.parentElement;
60
+ }
61
+ return segments.join(" > ");
62
+ }
63
+ function getXPath(element, options = {}) {
64
+ const segments = [];
65
+ let current = element;
66
+ while (current && current.nodeType === 1) {
67
+ const tagName = getTagName(current);
68
+ const index = getSameTagIndex(current);
69
+ const shouldIncludeIndex = options.alwaysIncludeIndex || hasSameTagSibling(current);
70
+ segments.unshift(`${tagName}${shouldIncludeIndex ? `[${index}]` : ""}`);
71
+ if (tagName === "html") {
72
+ break;
73
+ }
74
+ current = current.parentElement;
75
+ }
76
+ return `/${segments.join("/")}`;
77
+ }
78
+ function getJSPath(element) {
79
+ return `document.querySelector(${JSON.stringify(getCssSelector(element))})`;
80
+ }
81
+ function getElementPath(element, options = {}) {
82
+ const rootDocument = options.rootDocument ?? element.ownerDocument;
83
+ const selector = getCssSelector(element);
84
+ const xpath = getXPath(element);
85
+ const fullXPath = getXPath(element, { alwaysIncludeIndex: true });
86
+ const bridges = collectAccessBridges(element, rootDocument);
87
+ const orderedBridges = [...bridges].reverse();
88
+ const framePath = [];
89
+ const shadowPath = [];
90
+ let expression = "document";
91
+ for (const bridge of orderedBridges) {
92
+ if (bridge.kind === "iframe") {
93
+ const frameExpression = `${expression}.querySelector(${JSON.stringify(
94
+ bridge.selector
95
+ )})`;
96
+ framePath.push({
97
+ element: bridge.element,
98
+ selector: bridge.selector,
99
+ xpath: bridge.xpath,
100
+ fullXPath: bridge.fullXPath,
101
+ jsPath: frameExpression
102
+ });
103
+ expression = `${frameExpression}.contentDocument`;
104
+ continue;
105
+ }
106
+ const hostExpression = `${expression}.querySelector(${JSON.stringify(
107
+ bridge.selector
108
+ )})`;
109
+ shadowPath.push({
110
+ host: bridge.host,
111
+ hostSelector: bridge.selector,
112
+ hostXPath: bridge.xpath,
113
+ hostFullXPath: bridge.fullXPath,
114
+ jsPath: hostExpression
115
+ });
116
+ expression = `${hostExpression}.shadowRoot`;
117
+ }
118
+ return {
119
+ rootKind: getRootKind(bridges),
120
+ selector,
121
+ xpath,
122
+ fullXPath,
123
+ jsPath: `${expression}.querySelector(${JSON.stringify(selector)})`,
124
+ framePath,
125
+ shadowPath
126
+ };
127
+ }
128
+ function getCssSegment(element) {
129
+ const tagName = getTagName(element);
130
+ if (ROOT_TAGS.has(tagName)) {
131
+ return tagName;
132
+ }
133
+ if (!hasSameTagSibling(element)) {
134
+ return tagName;
135
+ }
136
+ return `${tagName}:nth-child(${getElementIndex(element)})`;
137
+ }
138
+ function getTagName(element) {
139
+ return element.localName.toLowerCase();
140
+ }
141
+ function getElementIndex(element) {
142
+ const siblings = getElementSiblings(element);
143
+ if (!siblings) {
144
+ return 1;
145
+ }
146
+ return siblings.indexOf(element) + 1;
147
+ }
148
+ function getSameTagIndex(element) {
149
+ const siblings = getElementSiblings(element);
150
+ if (!siblings) {
151
+ return 1;
152
+ }
153
+ const tagName = getTagName(element);
154
+ let index = 0;
155
+ for (const child of siblings) {
156
+ if (getTagName(child) === tagName) {
157
+ index += 1;
158
+ }
159
+ if (child === element) {
160
+ return index;
161
+ }
162
+ }
163
+ return 1;
164
+ }
165
+ function hasSameTagSibling(element) {
166
+ const siblings = getElementSiblings(element);
167
+ if (!siblings) {
168
+ return false;
169
+ }
170
+ const tagName = getTagName(element);
171
+ let count = 0;
172
+ for (const child of siblings) {
173
+ if (getTagName(child) === tagName) {
174
+ count += 1;
175
+ }
176
+ if (count > 1) {
177
+ return true;
178
+ }
179
+ }
180
+ return false;
181
+ }
182
+ function collectAccessBridges(element, rootDocument) {
183
+ const bridges = [];
184
+ let current = element;
185
+ let root = current.getRootNode();
186
+ while (true) {
187
+ if (isShadowRoot(root)) {
188
+ const host = root.host;
189
+ bridges.push({
190
+ kind: "shadow",
191
+ host,
192
+ selector: getCssSelector(host),
193
+ xpath: getXPath(host),
194
+ fullXPath: getXPath(host, { alwaysIncludeIndex: true })
195
+ });
196
+ current = host;
197
+ root = current.getRootNode();
198
+ continue;
199
+ }
200
+ if (isDocument(root) && root !== rootDocument) {
201
+ const frameElement = findFrameElementForDocument(root, rootDocument);
202
+ if (!frameElement) {
203
+ break;
204
+ }
205
+ bridges.push({
206
+ kind: "iframe",
207
+ element: frameElement,
208
+ selector: getCssSelector(frameElement),
209
+ xpath: getXPath(frameElement),
210
+ fullXPath: getXPath(frameElement, { alwaysIncludeIndex: true })
211
+ });
212
+ current = frameElement;
213
+ root = current.getRootNode();
214
+ continue;
215
+ }
216
+ break;
217
+ }
218
+ return bridges;
219
+ }
220
+ function getRootKind(bridges) {
221
+ const innermostBridge = bridges[0];
222
+ if (!innermostBridge) {
223
+ return "document";
224
+ }
225
+ return innermostBridge.kind === "shadow" ? "shadow" : "iframe";
226
+ }
227
+ function findFrameElementForDocument(targetDocument, searchDocument) {
228
+ const directFrame = targetDocument.defaultView?.frameElement;
229
+ if (directFrame && getTagName(directFrame) === "iframe") {
230
+ return directFrame;
231
+ }
232
+ for (const frame of Array.from(searchDocument.querySelectorAll("iframe"))) {
233
+ const childDocument = getAccessibleFrameDocument(frame);
234
+ if (!childDocument) {
235
+ continue;
236
+ }
237
+ if (childDocument === targetDocument) {
238
+ return frame;
239
+ }
240
+ const nestedFrame = findFrameElementForDocument(
241
+ targetDocument,
242
+ childDocument
243
+ );
244
+ if (nestedFrame) {
245
+ return nestedFrame;
246
+ }
247
+ }
248
+ return null;
249
+ }
250
+ function getAccessibleFrameDocument(frame) {
251
+ try {
252
+ return frame.contentDocument?.documentElement ? frame.contentDocument : null;
253
+ } catch {
254
+ return null;
255
+ }
256
+ }
257
+ function getElementSiblings(element) {
258
+ if (element.parentElement) {
259
+ return Array.from(element.parentElement.children);
260
+ }
261
+ const parentNode = element.parentNode;
262
+ if (!parentNode || parentNode.nodeType !== 11) {
263
+ return null;
264
+ }
265
+ return Array.from(parentNode.childNodes).filter(isElement);
266
+ }
267
+ function isDocument(root) {
268
+ return root.nodeType === 9;
269
+ }
270
+ function isElement(node) {
271
+ return node.nodeType === 1;
272
+ }
273
+ function isShadowRoot(root) {
274
+ return root.nodeType === 11 && "host" in root;
275
+ }
276
+
277
+ // src/pseudo.ts
278
+ var PSEUDO_ELEMENTS = ["::after", "::before"];
279
+ var HIT_SLOP = 4;
280
+ function getPseudoElementMatch(element, clientX, clientY) {
281
+ const pseudoElements = getPseudoElements(element);
282
+ for (const info of pseudoElements) {
283
+ if (!info.rect) {
284
+ continue;
285
+ }
286
+ if (containsPoint(info.rect, clientX, clientY, HIT_SLOP)) {
287
+ return {
288
+ hit: { pseudoElement: info.pseudoElement, rect: info.rect },
289
+ pseudoElements
290
+ };
291
+ }
292
+ }
293
+ return { hit: null, pseudoElements };
294
+ }
295
+ function getPseudoElements(element) {
296
+ const view = element.ownerDocument.defaultView;
297
+ if (!view) {
298
+ return [];
299
+ }
300
+ const pseudoElements = [];
301
+ for (const pseudoElement of PSEUDO_ELEMENTS) {
302
+ if (!hasVisiblePseudoElement(element, pseudoElement)) {
303
+ continue;
304
+ }
305
+ pseudoElements.push({
306
+ pseudoElement,
307
+ rect: getPseudoElementRect(element, pseudoElement)
308
+ });
309
+ }
310
+ return pseudoElements;
311
+ }
312
+ function getPseudoElementRect(element, pseudoElement) {
313
+ const view = element.ownerDocument.defaultView;
314
+ if (!view) {
315
+ return null;
316
+ }
317
+ const style = view.getComputedStyle(element, pseudoElement);
318
+ if (!isVisiblePseudoStyle(style)) {
319
+ return null;
320
+ }
321
+ const baseRect = element.getBoundingClientRect();
322
+ const leftInset = readLength(style.left, baseRect.width);
323
+ const rightInset = readLength(style.right, baseRect.width);
324
+ const topInset = readLength(style.top, baseRect.height);
325
+ const bottomInset = readLength(style.bottom, baseRect.height);
326
+ let width = readLength(style.width, baseRect.width);
327
+ let height = readLength(style.height, baseRect.height);
328
+ const hasGeometrySignal = style.position === "absolute" || style.position === "fixed" || width !== null || height !== null || leftInset !== null || rightInset !== null || topInset !== null || bottomInset !== null;
329
+ if (!hasGeometrySignal) {
330
+ return null;
331
+ }
332
+ if (width === null && leftInset !== null && rightInset !== null) {
333
+ width = Math.max(baseRect.width - leftInset - rightInset, 0);
334
+ }
335
+ if (height === null && topInset !== null && bottomInset !== null) {
336
+ height = Math.max(baseRect.height - topInset - bottomInset, 0);
337
+ }
338
+ if (width === null || height === null) {
339
+ return null;
340
+ }
341
+ const x = leftInset !== null ? baseRect.left + leftInset : rightInset !== null ? baseRect.right - rightInset - width : pseudoElement === "::before" ? baseRect.left : baseRect.right - width;
342
+ const y = topInset !== null ? baseRect.top + topInset : bottomInset !== null ? baseRect.bottom - bottomInset - height : pseudoElement === "::before" ? baseRect.top : baseRect.bottom - height;
343
+ return {
344
+ x,
345
+ y,
346
+ top: y,
347
+ left: x,
348
+ width,
349
+ height,
350
+ right: x + width,
351
+ bottom: y + height
352
+ };
353
+ }
354
+ function hasVisiblePseudoElement(element, pseudoElement) {
355
+ const view = element.ownerDocument.defaultView;
356
+ if (!view) {
357
+ return false;
358
+ }
359
+ return isVisiblePseudoStyle(view.getComputedStyle(element, pseudoElement));
360
+ }
361
+ function isVisiblePseudoStyle(style) {
362
+ return Boolean(
363
+ style && style.display !== "none" && style.visibility !== "hidden" && style.content !== "none" && style.content !== "normal"
364
+ );
365
+ }
366
+ function containsPoint(rect, clientX, clientY, slop) {
367
+ return clientX >= rect.left - slop && clientX <= rect.right + slop && clientY >= rect.top - slop && clientY <= rect.bottom + slop;
368
+ }
369
+ function readLength(value, basis) {
370
+ if (!value || value === "auto") {
371
+ return null;
372
+ }
373
+ if (value.endsWith("%")) {
374
+ const percentage = Number.parseFloat(value);
375
+ return Number.isFinite(percentage) ? basis * percentage / 100 : null;
376
+ }
377
+ const pixels = Number.parseFloat(value);
378
+ return Number.isFinite(pixels) ? pixels : null;
379
+ }
380
+
381
+ // src/inspector.ts
382
+ function createDOMInspector(options) {
383
+ return new DOMInspectorController(options);
384
+ }
385
+ var DOMInspectorController = class {
386
+ constructor(options) {
387
+ __publicField(this, "options", options);
388
+ __publicField(this, "document");
389
+ __publicField(this, "frameLoadHandlers", /* @__PURE__ */ new Map());
390
+ __publicField(this, "managedDocuments", /* @__PURE__ */ new Map());
391
+ __publicField(this, "selectionScope");
392
+ __publicField(this, "active", false);
393
+ __publicField(this, "hoveredElement", null);
394
+ __publicField(this, "hoveredPseudoElement", null);
395
+ __publicField(this, "hoveredPath", []);
396
+ __publicField(this, "hoveredPathIndex", 0);
397
+ __publicField(this, "handleMouseMove", (event) => {
398
+ const path = this.getInspectablePath(event);
399
+ const target = path[0];
400
+ if (!target) {
401
+ return;
402
+ }
403
+ const nextIndex = this.hoveredPath[0] === target ? Math.min(this.hoveredPathIndex, path.length - 1) : 0;
404
+ this.hoveredPath = path;
405
+ this.hoveredPathIndex = nextIndex;
406
+ this.updateHoveredElement(path[nextIndex], event);
407
+ });
408
+ __publicField(this, "handleMouseDown", (event) => {
409
+ if (event.button !== 0) {
410
+ return;
411
+ }
412
+ const target = this.getInspectablePath(event)[0];
413
+ if (!target) {
414
+ return;
415
+ }
416
+ if (this.options.preventDefault !== false) {
417
+ event.preventDefault();
418
+ event.stopPropagation();
419
+ event.stopImmediatePropagation();
420
+ }
421
+ });
422
+ __publicField(this, "handleClick", (event) => {
423
+ const path = this.getInspectablePath(event);
424
+ const target = this.getClickTarget(path);
425
+ if (!target) {
426
+ return;
427
+ }
428
+ const result = this.createResult(target, event);
429
+ if (this.options.preventDefault !== false) {
430
+ event.preventDefault();
431
+ event.stopPropagation();
432
+ event.stopImmediatePropagation();
433
+ }
434
+ this.showHighlight(result);
435
+ try {
436
+ this.options.onSelect?.(result);
437
+ } finally {
438
+ if (this.options.autoStop !== false) {
439
+ this.stop();
440
+ }
441
+ }
442
+ });
443
+ __publicField(this, "handleWheel", (event) => {
444
+ if (!this.selectionScope || !hasModifierKey(event, this.selectionScope.modifierKey)) {
445
+ return;
446
+ }
447
+ const direction = getWheelDirection(event);
448
+ if (direction === 0) {
449
+ return;
450
+ }
451
+ const path = this.getInspectablePath(event);
452
+ if (path.length > 0 && path[0] !== this.hoveredPath[0]) {
453
+ this.hoveredPath = path;
454
+ this.hoveredPathIndex = 0;
455
+ }
456
+ if (this.hoveredPath.length === 0) {
457
+ return;
458
+ }
459
+ event.preventDefault();
460
+ event.stopPropagation();
461
+ event.stopImmediatePropagation();
462
+ const nextIndex = clamp(
463
+ this.hoveredPathIndex + direction,
464
+ 0,
465
+ this.hoveredPath.length - 1
466
+ );
467
+ if (nextIndex === this.hoveredPathIndex) {
468
+ return;
469
+ }
470
+ this.hoveredPathIndex = nextIndex;
471
+ this.updateHoveredElement(this.hoveredPath[nextIndex], event);
472
+ });
473
+ __publicField(this, "handleKeyDown", (event) => {
474
+ if (event.key !== "Escape") {
475
+ return;
476
+ }
477
+ event.preventDefault();
478
+ this.stop();
479
+ this.options.onCancel?.();
480
+ });
481
+ __publicField(this, "handleViewportChange", () => {
482
+ if (!this.hoveredElement) {
483
+ return;
484
+ }
485
+ const highlighter = this.getHighlighter(this.hoveredElement.ownerDocument);
486
+ if (highlighter) {
487
+ this.hideInactiveHighlighters(this.hoveredElement.ownerDocument);
488
+ highlighter.show(this.hoveredElement);
489
+ }
490
+ });
491
+ this.document = options.document ?? document;
492
+ this.selectionScope = getSelectionScope(options.selectionScope);
493
+ }
494
+ start() {
495
+ if (this.active) {
496
+ return;
497
+ }
498
+ this.active = true;
499
+ this.attachDocument(this.document);
500
+ }
501
+ stop() {
502
+ if (!this.active) {
503
+ return;
504
+ }
505
+ this.active = false;
506
+ this.hoveredElement = null;
507
+ this.hoveredPseudoElement = null;
508
+ this.hoveredPath = [];
509
+ this.hoveredPathIndex = 0;
510
+ for (const [frame, handler] of this.frameLoadHandlers) {
511
+ frame.removeEventListener("load", handler);
512
+ }
513
+ this.frameLoadHandlers.clear();
514
+ for (const state of this.managedDocuments.values()) {
515
+ state.document.documentElement.style.cursor = state.previousCursor;
516
+ state.document.removeEventListener("mousemove", this.handleMouseMove, true);
517
+ state.document.removeEventListener("mousedown", this.handleMouseDown, true);
518
+ state.document.removeEventListener("click", this.handleClick, true);
519
+ state.document.removeEventListener("keydown", this.handleKeyDown, true);
520
+ state.document.removeEventListener("wheel", this.handleWheel, true);
521
+ state.document.defaultView?.removeEventListener(
522
+ "scroll",
523
+ this.handleViewportChange,
524
+ true
525
+ );
526
+ state.document.defaultView?.removeEventListener(
527
+ "resize",
528
+ this.handleViewportChange,
529
+ true
530
+ );
531
+ state.observer?.disconnect();
532
+ state.highlighter?.destroy();
533
+ }
534
+ this.managedDocuments.clear();
535
+ }
536
+ destroy() {
537
+ this.stop();
538
+ }
539
+ isActive() {
540
+ return this.active;
541
+ }
542
+ getInspectablePath(event) {
543
+ const path = event.composedPath().filter(isElementLike);
544
+ if (path.some((entry) => this.options.exclude?.(entry))) {
545
+ return [];
546
+ }
547
+ const inspectablePath = [];
548
+ for (const entry of path) {
549
+ if (this.managedDocuments.has(entry.ownerDocument) && !entry.hasAttribute("data-dom-inspector-overlay")) {
550
+ inspectablePath.push(entry);
551
+ }
552
+ }
553
+ if (inspectablePath.length > 0) {
554
+ return inspectablePath;
555
+ }
556
+ return isElementLike(event.target) && this.managedDocuments.has(event.target.ownerDocument) ? [event.target] : [];
557
+ }
558
+ getClickTarget(path) {
559
+ if (this.hoveredElement && path.includes(this.hoveredElement)) {
560
+ return this.hoveredElement;
561
+ }
562
+ return path[0] ?? null;
563
+ }
564
+ updateHoveredElement(element, event) {
565
+ const result = this.createResult(element, event);
566
+ if (element === this.hoveredElement && result.pseudoElement === this.hoveredPseudoElement) {
567
+ return;
568
+ }
569
+ this.hoveredElement = element;
570
+ this.hoveredPseudoElement = result.pseudoElement;
571
+ this.showHighlight(result);
572
+ this.options.onHover?.(result);
573
+ }
574
+ createResult(element, event) {
575
+ const path = getElementPath(element, { rootDocument: this.document });
576
+ const pseudoMatch = getPseudoElementMatch(
577
+ element,
578
+ event.clientX,
579
+ event.clientY
580
+ );
581
+ const pseudoHit = pseudoMatch.hit;
582
+ return {
583
+ ...path,
584
+ element,
585
+ ownerDocument: element.ownerDocument,
586
+ pseudoElement: pseudoHit?.pseudoElement ?? null,
587
+ pseudoElements: pseudoMatch.pseudoElements,
588
+ pseudoElementRect: pseudoHit?.rect ?? null,
589
+ rect: element.getBoundingClientRect(),
590
+ event,
591
+ selectorWithPseudo: pseudoHit ? `${path.selector}${pseudoHit.pseudoElement}` : path.selector
592
+ };
593
+ }
594
+ attachDocument(targetDocument) {
595
+ if (this.managedDocuments.has(targetDocument)) {
596
+ return;
597
+ }
598
+ const previousCursor = targetDocument.documentElement.style.cursor;
599
+ const highlighter = this.options.highlight === false ? null : new ElementHighlighter(
600
+ targetDocument,
601
+ typeof this.options.highlight === "object" ? this.options.highlight : void 0
602
+ );
603
+ const Observer = targetDocument.defaultView?.MutationObserver;
604
+ const observer = Observer ? new Observer(() => this.syncChildFrames(targetDocument)) : null;
605
+ targetDocument.documentElement.style.cursor = "crosshair";
606
+ targetDocument.addEventListener("mousemove", this.handleMouseMove, true);
607
+ targetDocument.addEventListener("mousedown", this.handleMouseDown, true);
608
+ targetDocument.addEventListener("click", this.handleClick, true);
609
+ targetDocument.addEventListener("keydown", this.handleKeyDown, true);
610
+ targetDocument.addEventListener("wheel", this.handleWheel, {
611
+ capture: true,
612
+ passive: false
613
+ });
614
+ targetDocument.defaultView?.addEventListener(
615
+ "scroll",
616
+ this.handleViewportChange,
617
+ true
618
+ );
619
+ targetDocument.defaultView?.addEventListener(
620
+ "resize",
621
+ this.handleViewportChange,
622
+ true
623
+ );
624
+ observer?.observe(targetDocument.documentElement, {
625
+ childList: true,
626
+ subtree: true
627
+ });
628
+ this.managedDocuments.set(targetDocument, {
629
+ document: targetDocument,
630
+ highlighter,
631
+ observer,
632
+ previousCursor
633
+ });
634
+ this.syncChildFrames(targetDocument);
635
+ }
636
+ syncChildFrames(targetDocument) {
637
+ for (const frame of Array.from(
638
+ targetDocument.querySelectorAll("iframe")
639
+ )) {
640
+ this.observeFrameLoad(frame);
641
+ const frameDocument = getAccessibleFrameDocument2(frame);
642
+ if (frameDocument) {
643
+ this.attachDocument(frameDocument);
644
+ }
645
+ }
646
+ }
647
+ observeFrameLoad(frame) {
648
+ if (this.frameLoadHandlers.has(frame)) {
649
+ return;
650
+ }
651
+ const handler = () => {
652
+ if (!this.active) {
653
+ return;
654
+ }
655
+ const frameDocument = getAccessibleFrameDocument2(frame);
656
+ if (frameDocument) {
657
+ this.attachDocument(frameDocument);
658
+ }
659
+ };
660
+ frame.addEventListener("load", handler);
661
+ this.frameLoadHandlers.set(frame, handler);
662
+ }
663
+ showHighlight(result) {
664
+ const highlighter = this.getHighlighter(result.element.ownerDocument);
665
+ if (!highlighter) {
666
+ return;
667
+ }
668
+ this.hideInactiveHighlighters(result.element.ownerDocument);
669
+ if (result.pseudoElementRect) {
670
+ highlighter.showRect(result.pseudoElementRect);
671
+ return;
672
+ }
673
+ highlighter.show(result.element);
674
+ }
675
+ hideInactiveHighlighters(activeDocument) {
676
+ for (const state of this.managedDocuments.values()) {
677
+ if (state.document !== activeDocument) {
678
+ state.highlighter?.hide();
679
+ }
680
+ }
681
+ }
682
+ getHighlighter(targetDocument) {
683
+ return this.managedDocuments.get(targetDocument)?.highlighter ?? null;
684
+ }
685
+ };
686
+ function getAccessibleFrameDocument2(frame) {
687
+ try {
688
+ return frame.contentDocument?.documentElement ? frame.contentDocument : null;
689
+ } catch {
690
+ return null;
691
+ }
692
+ }
693
+ function getSelectionScope(options) {
694
+ if (options === false) {
695
+ return null;
696
+ }
697
+ return {
698
+ modifierKey: options?.modifierKey ?? "Alt"
699
+ };
700
+ }
701
+ function hasModifierKey(event, modifierKey) {
702
+ switch (modifierKey) {
703
+ case "Alt":
704
+ return event.altKey;
705
+ case "Control":
706
+ return event.ctrlKey;
707
+ case "Meta":
708
+ return event.metaKey;
709
+ case "Shift":
710
+ return event.shiftKey;
711
+ }
712
+ }
713
+ function getWheelDirection(event) {
714
+ if (event.deltaY < 0) {
715
+ return 1;
716
+ }
717
+ if (event.deltaY > 0) {
718
+ return -1;
719
+ }
720
+ return 0;
721
+ }
722
+ function clamp(value, min, max) {
723
+ return Math.min(Math.max(value, min), max);
724
+ }
725
+ function isElementLike(value) {
726
+ return typeof value === "object" && value !== null && value.nodeType === 1 && typeof value.tagName === "string";
727
+ }
728
+ export {
729
+ createDOMInspector,
730
+ getCssSelector,
731
+ getElementPath,
732
+ getJSPath,
733
+ getXPath
734
+ };
735
+ //# sourceMappingURL=index.js.map