@abbox/inspector 0.4.11 → 0.4.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"client-bridge.d.ts","sourceRoot":"","sources":["../../src/host/client-bridge.ts"],"names":[],"mappings":"AAWA,MAAM,MAAM,sBAAsB,GAAG;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,kBAAkB,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,IAAI,EAAE,MAAM,IAAI,CAAC;CAClB,CAAC;AAEF,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,sBAAsB,GAC9B,eAAe,CA2FjB"}
1
+ {"version":3,"file":"client-bridge.d.ts","sourceRoot":"","sources":["../../src/host/client-bridge.ts"],"names":[],"mappings":"AAWA,MAAM,MAAM,sBAAsB,GAAG;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,kBAAkB,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,IAAI,EAAE,MAAM,IAAI,CAAC;CAClB,CAAC;AAEF,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,sBAAsB,GAC9B,eAAe,CA4EjB"}
@@ -9,26 +9,8 @@ export function createInspectorClient(options) {
9
9
  const send = (message) => {
10
10
  if (!win.parent || win.parent === win)
11
11
  return;
12
- let sent = false;
13
- // Try each allowed origin
14
12
  for (const targetOrigin of allowedOrigins) {
15
- try {
16
- win.parent.postMessage(message, targetOrigin);
17
- sent = true;
18
- break;
19
- }
20
- catch (err) {
21
- // Try next origin
22
- }
23
- }
24
- // If all allowed origins failed, try wildcard
25
- if (!sent) {
26
- try {
27
- win.parent.postMessage(message, "*");
28
- }
29
- catch (err) {
30
- // Give up silently
31
- }
13
+ win.parent.postMessage(message, targetOrigin);
32
14
  }
33
15
  };
34
16
  const base = () => ({
@@ -59,6 +41,9 @@ export function createInspectorClient(options) {
59
41
  onChangeMarkerSelected: (changeId) => {
60
42
  send({ ...base(), type: "CHANGE_MARKER_SELECTED", changeId });
61
43
  },
44
+ onRouteChange: (path) => {
45
+ send({ ...base(), type: "ROUTE_CHANGED", path });
46
+ },
62
47
  });
63
48
  const onMessage = (event) => {
64
49
  const msg = validateIncomingMessage(event.data, event.origin, {
@@ -19,6 +19,7 @@ export type InspectorHostHandlers = {
19
19
  onSelect?: (payload: SelectPayload) => void;
20
20
  onCleared?: () => void;
21
21
  onChangeMarkerSelected?: (changeId: string) => void;
22
+ onRouteChange?: (path: string) => void;
22
23
  onError?: (code: string, message: string) => void;
23
24
  };
24
25
  export type InspectorHost = {
@@ -1 +1 @@
1
- {"version":3,"file":"host-bridge.d.ts","sourceRoot":"","sources":["../../src/host/host-bridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,mBAAmB,EAGzB,MAAM,gBAAgB,CAAC;AAIxB,MAAM,MAAM,oBAAoB,GAAG;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,0DAA0D;IAC1D,aAAa,EAAE,MAAM,CAAC;IACtB,mDAAmD;IACnD,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;CACvC,CAAC;AAEF,KAAK,YAAY,GAAG,OAAO,CACzB,mBAAmB,EACnB;IAAE,IAAI,EAAE,iBAAiB,CAAA;CAAE,CAC5B,CAAC,SAAS,CAAC,CAAC;AACb,KAAK,aAAa,GAAG,OAAO,CAC1B,mBAAmB,EACnB;IAAE,IAAI,EAAE,kBAAkB,CAAA;CAAE,CAC7B,CAAC,SAAS,CAAC,CAAC;AAEb,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,IAAI,CAAC;IAC1C,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAC;IAC5C,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,sBAAsB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACnD,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,kBAAkB,EAAE,CAAC,OAAO,EAAE,YAAY,EAAE,KAAK,IAAI,CAAC;IACtD,0EAA0E;IAC1E,WAAW,EAAE,MAAM,IAAI,CAAC;CACzB,CAAC;AAEF,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,oBAAoB,EAC7B,QAAQ,EAAE,qBAAqB,GAC9B,aAAa,CA+Df"}
1
+ {"version":3,"file":"host-bridge.d.ts","sourceRoot":"","sources":["../../src/host/host-bridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,mBAAmB,EAGzB,MAAM,gBAAgB,CAAC;AAIxB,MAAM,MAAM,oBAAoB,GAAG;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,0DAA0D;IAC1D,aAAa,EAAE,MAAM,CAAC;IACtB,mDAAmD;IACnD,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;CACvC,CAAC;AAEF,KAAK,YAAY,GAAG,OAAO,CACzB,mBAAmB,EACnB;IAAE,IAAI,EAAE,iBAAiB,CAAA;CAAE,CAC5B,CAAC,SAAS,CAAC,CAAC;AACb,KAAK,aAAa,GAAG,OAAO,CAC1B,mBAAmB,EACnB;IAAE,IAAI,EAAE,kBAAkB,CAAA;CAAE,CAC7B,CAAC,SAAS,CAAC,CAAC;AAEb,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,IAAI,CAAC;IAC1C,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAC;IAC5C,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,sBAAsB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACnD,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,kBAAkB,EAAE,CAAC,OAAO,EAAE,YAAY,EAAE,KAAK,IAAI,CAAC;IACtD,0EAA0E;IAC1E,WAAW,EAAE,MAAM,IAAI,CAAC;CACzB,CAAC;AAEF,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,oBAAoB,EAC7B,QAAQ,EAAE,qBAAqB,GAC9B,aAAa,CAkEf"}
@@ -35,6 +35,9 @@ export function createInspectorHost(options, handlers) {
35
35
  if (msg.type === "CHANGE_MARKER_SELECTED") {
36
36
  handlers.onChangeMarkerSelected?.(msg.changeId);
37
37
  }
38
+ if (msg.type === "ROUTE_CHANGED") {
39
+ handlers.onRouteChange?.(msg.path);
40
+ }
38
41
  if (msg.type === "INSPECTOR_ERROR") {
39
42
  handlers.onError?.(msg.code, msg.message);
40
43
  }
@@ -1 +1 @@
1
- {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/host/validate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,gBAAgB,EAAsB,MAAM,gBAAgB,CAAC;AAE3E,MAAM,MAAM,eAAe,GAAG;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC,CAAC;AAEF,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,OAAO,EACb,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,eAAe,GACvB,gBAAgB,GAAG,IAAI,CAKzB;AAED,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,gBAAgB,EACzB,YAAY,EAAE,MAAM,GACnB,IAAI,CA6BN"}
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/host/validate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,gBAAgB,EAAsB,MAAM,gBAAgB,CAAC;AAE3E,MAAM,MAAM,eAAe,GAAG;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC,CAAC;AAEF,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,OAAO,EACb,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,eAAe,GACvB,gBAAgB,GAAG,IAAI,CAKzB;AAED,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,gBAAgB,EACzB,YAAY,EAAE,MAAM,GACnB,IAAI,CAEN"}
@@ -9,32 +9,5 @@ export function validateIncomingMessage(data, origin, options) {
9
9
  return data;
10
10
  }
11
11
  export function postToTarget(target, message, targetOrigin) {
12
- // Try primary origin first
13
- try {
14
- target.postMessage(message, targetOrigin);
15
- return;
16
- }
17
- catch {
18
- // Silently fail and try fallback
19
- }
20
- // Try localhost/127.0.0.1 variant
21
- const variant = targetOrigin
22
- .replace("://localhost", "://127.0.0.1")
23
- .replace("://127.0.0.1", "://localhost");
24
- if (variant !== targetOrigin) {
25
- try {
26
- target.postMessage(message, variant);
27
- return;
28
- }
29
- catch {
30
- // Silently fail and try wildcard
31
- }
32
- }
33
- // Last resort: wildcard (bypasses origin check)
34
- try {
35
- target.postMessage(message, "*");
36
- }
37
- catch {
38
- // Give up silently
39
- }
12
+ target.postMessage(message, targetOrigin);
40
13
  }
@@ -47,6 +47,21 @@ export type ElementMetadata = {
47
47
  /** Native disabled state when the element supports it (e.g. button, input). */
48
48
  disabled: boolean | null;
49
49
  attributes: Record<string, string>;
50
+ /**
51
+ * Live state of form controls near the element (its form, or the nearest
52
+ * container with controls). Values are never included, only whether filled.
53
+ */
54
+ nearbyFields?: NearbyFieldState[];
55
+ };
56
+ export type NearbyFieldState = {
57
+ tagName: string;
58
+ type: string | null;
59
+ label: string | null;
60
+ placeholder: string | null;
61
+ required: boolean;
62
+ disabled: boolean;
63
+ state: "empty" | "filled" | "checked" | "unchecked";
64
+ isSelected: boolean;
50
65
  };
51
66
  export type RuntimeElementRef = {
52
67
  /** Stable within a preview session for a given DOM node identity. */
@@ -94,12 +109,17 @@ export type ChangeMarkerSelectedMessage = InspectorMessageBase & {
94
109
  type: "CHANGE_MARKER_SELECTED";
95
110
  changeId: string;
96
111
  };
112
+ /** The preview navigated (client-side or full load) to a new path. */
113
+ export type RouteChangedMessage = InspectorMessageBase & {
114
+ type: "ROUTE_CHANGED";
115
+ path: string;
116
+ };
97
117
  export type ApplyChangeMarkersMessage = InspectorMessageBase & {
98
118
  type: "APPLY_CHANGE_MARKERS";
99
119
  markers: ChangeMarker[];
100
120
  };
101
121
  export type HostToClientMessage = InspectorEnableMessage | InspectorDisableMessage | InspectorHostHelloMessage | ApplyChangeMarkersMessage;
102
- export type ClientToHostMessage = InspectorReadyMessage | ElementHoveredMessage | ElementSelectedMessage | ElementClearedMessage | ChangeMarkerSelectedMessage | InspectorErrorMessage;
122
+ export type ClientToHostMessage = InspectorReadyMessage | ElementHoveredMessage | ElementSelectedMessage | ElementClearedMessage | ChangeMarkerSelectedMessage | RouteChangedMessage | InspectorErrorMessage;
103
123
  export type InspectorMessage = HostToClientMessage | ClientToHostMessage;
104
124
  export declare function isInspectorMessage(value: unknown): value is InspectorMessage;
105
125
  //# sourceMappingURL=protocol.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../src/runtime/bootstrap.ts"],"names":[],"mappings":"AAuCA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,YAAY,CAAC,EAAE,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACzD,CAAC;AA8CF;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,GAAE,gBAAqB,GAC7B,IAAI,CAiDN;AAED,4CAA4C;AAC5C,wBAAgB,+BAA+B,IAAI,IAAI,CAMtD"}
1
+ {"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../src/runtime/bootstrap.ts"],"names":[],"mappings":"AAuCA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,YAAY,CAAC,EAAE,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACzD,CAAC;AA8CF;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,GAAE,gBAAqB,GAC7B,IAAI,CAkDN;AAED,4CAA4C;AAC5C,wBAAgB,+BAA+B,IAAI,IAAI,CAMtD"}
@@ -75,9 +75,10 @@ export function bootstrapInspectorPreview(options = {}) {
75
75
  // In Next.js 13+ RSC, window.location.search may be empty. Fallback to passed searchParams.
76
76
  let params;
77
77
  if (options.searchParams) {
78
- params = options.searchParams instanceof URLSearchParams
79
- ? options.searchParams
80
- : new URLSearchParams(options.searchParams);
78
+ params =
79
+ options.searchParams instanceof URLSearchParams
80
+ ? options.searchParams
81
+ : new URLSearchParams(options.searchParams);
81
82
  }
82
83
  else {
83
84
  params = new URLSearchParams(win.location.search);
@@ -6,6 +6,7 @@ export type InspectorRuntimeOptions = {
6
6
  onSelect?: (payload: ElementHoverPayload) => void;
7
7
  onClear?: () => void;
8
8
  onChangeMarkerSelected?: (changeId: string) => void;
9
+ onRouteChange?: (path: string) => void;
9
10
  };
10
11
  export type InspectorRuntime = {
11
12
  enable: () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"inspector.d.ts","sourceRoot":"","sources":["../../src/runtime/inspector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAkBxE,MAAM,MAAM,uBAAuB,GAAG;IACpC,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACjD,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAClD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,sBAAsB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;CACrD,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,SAAS,EAAE,MAAM,OAAO,CAAC;IACzB,gBAAgB,EAAE,CAAC,OAAO,EAAE,YAAY,EAAE,KAAK,IAAI,CAAC;IACpD,iBAAiB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,GAAG,IAAI,CAAC;IACrD,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,uBAAuB,GAC/B,gBAAgB,CA0OlB"}
1
+ {"version":3,"file":"inspector.d.ts","sourceRoot":"","sources":["../../src/runtime/inspector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAyCxE,MAAM,MAAM,uBAAuB,GAAG;IACpC,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACjD,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAClD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,sBAAsB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,SAAS,EAAE,MAAM,OAAO,CAAC;IACzB,gBAAgB,EAAE,CAAC,OAAO,EAAE,YAAY,EAAE,KAAK,IAAI,CAAC;IACpD,iBAAiB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,GAAG,IAAI,CAAC;IACrD,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,uBAAuB,GAC/B,gBAAgB,CAkTlB"}
@@ -1,6 +1,23 @@
1
1
  import { runtimeElementRefFor } from "./element-ref.js";
2
2
  import { extractMetadata, findSourceLocation, sourceKeyFor, sourceMappingStatus, } from "./metadata.js";
3
3
  import { createOverlay, hideHighlight, hideSelectedHighlight, positionHighlight, positionSelectedHighlight, rectForElement, renderChangeMarkers, } from "./overlay.js";
4
+ const SOURCE_LINE_TOLERANCE = 2;
5
+ function parseSourceKey(raw) {
6
+ const m = raw ? /^(.*?):(\d+)(?::\d+)?$/.exec(raw) : null;
7
+ return m?.[1] ? { file: m[1], line: Number(m[2]) } : null;
8
+ }
9
+ function sameFile(a, b) {
10
+ return a === b || a.endsWith(`/${b}`) || b.endsWith(`/${a}`);
11
+ }
12
+ const SWALLOWED_EVENTS = [
13
+ "pointerup",
14
+ "mousedown",
15
+ "mouseup",
16
+ "click",
17
+ "dblclick",
18
+ "auxclick",
19
+ "contextmenu",
20
+ ];
4
21
  export function createInspectorRuntime(options) {
5
22
  const { document: doc, window: win } = options;
6
23
  const overlay = createOverlay(doc);
@@ -15,6 +32,35 @@ export function createInspectorRuntime(options) {
15
32
  const teardownListeners = () => {
16
33
  win.removeEventListener("mousemove", onMove, true);
17
34
  win.removeEventListener("pointerdown", onPointerDownCapture, true);
35
+ doc.removeEventListener("mouseout", onLeave, true);
36
+ for (const type of SWALLOWED_EVENTS) {
37
+ win.removeEventListener(type, swallowAppInteraction, true);
38
+ }
39
+ };
40
+ const isChangeMarker = (target) => target instanceof Element &&
41
+ target.closest("[data-abbox-change-marker]") !== null;
42
+ /**
43
+ * While inspecting, a click only selects. Cancelling pointerdown alone does
44
+ * not stop the mousedown/mouseup/click that follow, so the app would still
45
+ * react (navigate, submit, open modals).
46
+ */
47
+ const swallowAppInteraction = (event) => {
48
+ if (!enabled || isChangeMarker(event.target))
49
+ return;
50
+ event.preventDefault();
51
+ event.stopImmediatePropagation();
52
+ };
53
+ /** No mousemove fires once the pointer leaves the iframe, so clear hover here. */
54
+ const onLeave = (event) => {
55
+ if (event.relatedTarget)
56
+ return;
57
+ if (raf) {
58
+ win.cancelAnimationFrame(raf);
59
+ raf = 0;
60
+ }
61
+ pendingTarget = null;
62
+ hovered = null;
63
+ hideHighlight(overlay.highlight);
18
64
  };
19
65
  const onMove = (event) => {
20
66
  if (!enabled)
@@ -37,13 +83,12 @@ export function createInspectorRuntime(options) {
37
83
  const onPointerDownCapture = (event) => {
38
84
  if (!enabled)
39
85
  return;
40
- if (event.button !== 0)
41
- return;
42
- if (event.target instanceof Element &&
43
- event.target.closest("[data-abbox-change-marker]"))
86
+ if (isChangeMarker(event.target))
44
87
  return;
45
88
  event.preventDefault();
46
- event.stopPropagation();
89
+ event.stopImmediatePropagation();
90
+ if (event.button !== 0)
91
+ return;
47
92
  const target = deepestElementAt(doc, event.clientX, event.clientY, event.target);
48
93
  if (!target || !doc.body.contains(target))
49
94
  return;
@@ -81,56 +126,120 @@ export function createInspectorRuntime(options) {
81
126
  options.onHover?.(payloadFor(el));
82
127
  }
83
128
  function select(el) {
84
- console.log("[inspector] element selected", el.tagName);
85
129
  selected = el;
86
130
  hovered = el;
87
131
  positionSelectedHighlight(overlay.selectedHighlight, rectForElement(el));
88
132
  positionHighlight(overlay.highlight, rectForElement(el));
89
133
  options.onSelect?.(payloadFor(el));
90
134
  }
91
- function resolveMarkerElements(next) {
135
+ const onCurrentRoute = (marker) => !marker.route ||
136
+ win.location.pathname.replace(/\/$/, "") ===
137
+ marker.route.replace(/\/$/, "");
138
+ function resolveMarkerElement(marker) {
92
139
  const isRendered = (node) => {
93
140
  const rect = node.getBoundingClientRect();
94
141
  return node.isConnected && rect.width > 0 && rect.height > 0;
95
142
  };
143
+ const target = parseSourceKey(marker.sourceKeyPrefix);
144
+ const byLine = new Map();
145
+ if (target) {
146
+ for (const node of Array.from(doc.querySelectorAll("[data-abbox-src]"))) {
147
+ const src = parseSourceKey(node.getAttribute("data-abbox-src"));
148
+ if (!src || !sameFile(src.file, target.file))
149
+ continue;
150
+ const distance = Math.abs(src.line - target.line);
151
+ if (distance > SOURCE_LINE_TOLERANCE || !isRendered(node))
152
+ continue;
153
+ byLine.set(distance, [...(byLine.get(distance) ?? []), node]);
154
+ }
155
+ }
156
+ const nearestDistance = Math.min(...byLine.keys());
157
+ const sourceCandidates = byLine.get(nearestDistance) ?? [];
158
+ const hint = marker.textHint?.trim();
159
+ const hasHint = (node) => node.textContent?.trim() === hint;
160
+ const sourceTextCandidates = hint ? sourceCandidates.filter(hasHint) : [];
161
+ const textCandidates = hint
162
+ ? Array.from(doc.querySelectorAll("body *")).filter((node) => node.children.length === 0 &&
163
+ isRendered(node) &&
164
+ hasHint(node) &&
165
+ !node.closest("[data-abbox-inspector]"))
166
+ : [];
167
+ if (sourceTextCandidates.length === 1)
168
+ return sourceTextCandidates[0] ?? null;
169
+ if (sourceCandidates.length === 1)
170
+ return sourceCandidates[0] ?? null;
171
+ if (textCandidates.length === 1)
172
+ return textCandidates[0] ?? null;
173
+ return null;
174
+ }
175
+ function resolveMarkerElements(next) {
96
176
  for (const marker of next) {
97
- if (marker.route &&
98
- win.location.pathname.replace(/\/$/, "") !==
99
- marker.route.replace(/\/$/, ""))
177
+ const cached = refIdToElement.get(marker.elementRefId);
178
+ if (cached?.isConnected && onCurrentRoute(marker))
100
179
  continue;
101
- if (refIdToElement.has(marker.elementRefId))
180
+ refIdToElement.delete(marker.elementRefId);
181
+ if (!onCurrentRoute(marker))
102
182
  continue;
103
- const sourceKey = marker.sourceKeyPrefix
104
- ? `${marker.sourceKeyPrefix}:`
105
- : null;
106
- const sourceCandidates = sourceKey
107
- ? Array.from(doc.querySelectorAll("[data-abbox-src]")).filter((node) => {
108
- const raw = node.getAttribute("data-abbox-src") ?? "";
109
- return (isRendered(node) &&
110
- (raw.startsWith(sourceKey) || raw.endsWith(`/${sourceKey}`)));
111
- })
112
- : [];
113
- const hint = marker.textHint?.trim();
114
- const textCandidates = hint
115
- ? Array.from(doc.querySelectorAll("body *")).filter((node) => node.children.length === 0 &&
116
- isRendered(node) &&
117
- node.textContent?.trim() === hint &&
118
- !node.closest("[data-abbox-inspector]"))
119
- : [];
120
- const sourceTextCandidates = hint
121
- ? sourceCandidates.filter((node) => node.textContent?.trim() === hint)
122
- : [];
123
- const match = sourceTextCandidates.length === 1
124
- ? sourceTextCandidates[0]
125
- : textCandidates.length === 1
126
- ? textCandidates[0]
127
- : !hint && sourceCandidates.length === 1
128
- ? sourceCandidates[0]
129
- : null;
183
+ const match = resolveMarkerElement(marker);
130
184
  if (match)
131
185
  refIdToElement.set(marker.elementRefId, match);
132
186
  }
133
187
  }
188
+ /** Selects the element of the change the host focused, once it renders. */
189
+ function focusPulsedMarker() {
190
+ const focused = markers.find((marker) => marker.pulse && refIdToElement.has(marker.elementRefId));
191
+ if (!focused) {
192
+ if (!markers.some((marker) => marker.pulse))
193
+ focusedMarkerId = null;
194
+ return;
195
+ }
196
+ if (focused.elementRefId === focusedMarkerId)
197
+ return;
198
+ focusedMarkerId = focused.elementRefId;
199
+ const el = refIdToElement.get(focused.elementRefId);
200
+ if (!el)
201
+ return;
202
+ el.scrollIntoView?.({ block: "center", inline: "nearest" });
203
+ select(el);
204
+ }
205
+ function refreshMarkers() {
206
+ resolveMarkerElements(markers);
207
+ focusPulsedMarker();
208
+ renderChangeMarkers(overlay.markerLayer, markers, (id) => refIdToElement.get(id) ?? null, options.onChangeMarkerSelected);
209
+ if (selected?.isConnected) {
210
+ positionSelectedHighlight(overlay.selectedHighlight, rectForElement(selected));
211
+ }
212
+ }
213
+ let lastPath = win.location.pathname;
214
+ let refreshFrame = 0;
215
+ /** SPA navigation and async data swap the DOM after markers arrive. */
216
+ const scheduleRefresh = () => {
217
+ if (refreshFrame)
218
+ return;
219
+ refreshFrame = win.requestAnimationFrame(() => {
220
+ refreshFrame = 0;
221
+ if (win.location.pathname !== lastPath) {
222
+ lastPath = win.location.pathname;
223
+ options.onRouteChange?.(lastPath);
224
+ }
225
+ if (markers.length)
226
+ refreshMarkers();
227
+ });
228
+ };
229
+ const observer = typeof MutationObserver === "undefined"
230
+ ? null
231
+ : new MutationObserver((records) => {
232
+ const ownChange = records.every((record) => record.target instanceof Element &&
233
+ record.target.closest("[data-abbox-inspector]") !== null);
234
+ if (!ownChange)
235
+ scheduleRefresh();
236
+ });
237
+ observer?.observe(doc.body, {
238
+ childList: true,
239
+ subtree: true,
240
+ characterData: true,
241
+ });
242
+ win.addEventListener("popstate", scheduleRefresh);
134
243
  function clearSelection() {
135
244
  hovered = null;
136
245
  selected = null;
@@ -147,6 +256,10 @@ export function createInspectorRuntime(options) {
147
256
  enabled = true;
148
257
  win.addEventListener("mousemove", onMove, true);
149
258
  win.addEventListener("pointerdown", onPointerDownCapture, true);
259
+ doc.addEventListener("mouseout", onLeave, true);
260
+ for (const type of SWALLOWED_EVENTS) {
261
+ win.addEventListener(type, swallowAppInteraction, true);
262
+ }
150
263
  },
151
264
  disable: () => {
152
265
  if (!enabled)
@@ -163,25 +276,7 @@ export function createInspectorRuntime(options) {
163
276
  markers = next;
164
277
  for (const marker of next)
165
278
  refIdToElement.delete(marker.elementRefId);
166
- resolveMarkerElements(next);
167
- const focused = next.find((marker) => marker.pulse && refIdToElement.has(marker.elementRefId));
168
- if (focused && focused.elementRefId !== focusedMarkerId) {
169
- refIdToElement
170
- .get(focused.elementRefId)
171
- ?.scrollIntoView?.({ block: "center", inline: "nearest" });
172
- }
173
- focusedMarkerId = focused?.elementRefId ?? null;
174
- const unresolved = next.filter((marker) => (!marker.route ||
175
- marker.route.replace(/\/$/, "") ===
176
- win.location.pathname.replace(/\/$/, "")) &&
177
- !refIdToElement.has(marker.elementRefId));
178
- if (unresolved.length) {
179
- console.warn("[abbox-inspector] change markers could not be matched to rendered elements", {
180
- route: win.location.pathname,
181
- changeIds: unresolved.map((marker) => marker.elementRefId),
182
- });
183
- }
184
- renderChangeMarkers(overlay.markerLayer, markers, (id) => refIdToElement.get(id) ?? null, options.onChangeMarkerSelected);
279
+ refreshMarkers();
185
280
  },
186
281
  getElementByRefId: (id) => refIdToElement.get(id) ?? null,
187
282
  destroy: () => {
@@ -191,6 +286,10 @@ export function createInspectorRuntime(options) {
191
286
  }
192
287
  win.removeEventListener("scroll", onScrollOrResize, true);
193
288
  win.removeEventListener("resize", onScrollOrResize);
289
+ win.removeEventListener("popstate", scheduleRefresh);
290
+ observer?.disconnect();
291
+ if (refreshFrame)
292
+ win.cancelAnimationFrame(refreshFrame);
194
293
  hovered = null;
195
294
  hideHighlight(overlay.highlight);
196
295
  overlay.destroy();
@@ -1 +1 @@
1
- {"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../../src/runtime/metadata.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,eAAe,EACf,cAAc,EACd,mBAAmB,EACpB,MAAM,gBAAgB,CAAC;AAYxB,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,OAAO,GAAG,cAAc,GAAG,IAAI,CAarE;AAED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,cAAc,GAAG,IAAI,GAC5B,mBAAmB,CAGrB;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,OAAO,GAAG,eAAe,CAiC5D;AA+BD,wBAAgB,YAAY,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAGzE"}
1
+ {"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../../src/runtime/metadata.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,eAAe,EAEf,cAAc,EACd,mBAAmB,EACpB,MAAM,gBAAgB,CAAC;AAYxB,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,OAAO,GAAG,cAAc,GAAG,IAAI,CAarE;AAED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,cAAc,GAAG,IAAI,GAC5B,mBAAmB,CAGrB;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,OAAO,GAAG,eAAe,CAkC5D;AA2FD,wBAAgB,YAAY,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAGzE"}
@@ -60,8 +60,62 @@ export function extractMetadata(el) {
60
60
  textPreview,
61
61
  disabled: readDisabledState(el),
62
62
  attributes,
63
+ nearbyFields: nearbyFieldStates(el),
63
64
  };
64
65
  }
66
+ const FIELD_SELECTOR = "input:not([type=hidden]), textarea, select";
67
+ const MAX_CONTAINER_HOPS = 4;
68
+ const MAX_NEARBY_FIELDS = 15;
69
+ function fieldContainer(el) {
70
+ const form = el.closest("form");
71
+ if (form)
72
+ return form;
73
+ let node = el.parentElement;
74
+ for (let hop = 0; node && hop < MAX_CONTAINER_HOPS; hop++) {
75
+ if (node.querySelector(FIELD_SELECTOR))
76
+ return node;
77
+ node = node.parentElement;
78
+ }
79
+ return null;
80
+ }
81
+ function fieldLabel(control) {
82
+ const text = control.getAttribute("aria-label") ??
83
+ control.labels?.[0]?.textContent ??
84
+ null;
85
+ return text?.trim().slice(0, 80) || null;
86
+ }
87
+ /** Field emptiness only; typed values never leave the preview. */
88
+ function nearbyFieldStates(el) {
89
+ const container = fieldContainer(el);
90
+ if (!container)
91
+ return undefined;
92
+ const controls = Array.from(container.querySelectorAll(FIELD_SELECTOR)).slice(0, MAX_NEARBY_FIELDS);
93
+ if (controls.length === 0)
94
+ return undefined;
95
+ return controls.map((control) => {
96
+ const type = control instanceof HTMLInputElement
97
+ ? control.type
98
+ : control.getAttribute("type");
99
+ const checkable = control instanceof HTMLInputElement &&
100
+ (control.type === "checkbox" || control.type === "radio");
101
+ return {
102
+ tagName: control.tagName.toLowerCase(),
103
+ type,
104
+ label: fieldLabel(control),
105
+ placeholder: control.getAttribute("placeholder"),
106
+ required: control.required,
107
+ disabled: control.disabled,
108
+ state: checkable
109
+ ? control.checked
110
+ ? "checked"
111
+ : "unchecked"
112
+ : control.value.trim()
113
+ ? "filled"
114
+ : "empty",
115
+ isSelected: control === el,
116
+ };
117
+ });
118
+ }
65
119
  function readDisabledState(el) {
66
120
  if (el instanceof HTMLButtonElement ||
67
121
  el instanceof HTMLInputElement ||
@@ -1 +1 @@
1
- {"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../../src/runtime/overlay.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAMhE,MAAM,MAAM,cAAc,GAAG;IAC3B,SAAS,EAAE,cAAc,CAAC;IAC1B,iBAAiB,EAAE,cAAc,CAAC;IAClC,WAAW,EAAE,cAAc,CAAC;IAC5B,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF,wBAAgB,aAAa,CAAC,IAAI,EAAE,QAAQ,GAAG,cAAc,CAiD5D;AAED,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,cAAc,EACzB,IAAI,EAAE,WAAW,GAChB,IAAI,CAQN;AAED,wBAAgB,yBAAyB,CACvC,iBAAiB,EAAE,cAAc,EACjC,IAAI,EAAE,WAAW,GAChB,IAAI,CASN;AAED,wBAAgB,aAAa,CAAC,SAAS,EAAE,cAAc,GAAG,IAAI,CAE7D;AAED,wBAAgB,qBAAqB,CAAC,iBAAiB,EAAE,cAAc,GAAG,IAAI,CAE7E;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,OAAO,GAAG,WAAW,CAQvD;AAOD,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,cAAc,EACrB,OAAO,EAAE,YAAY,EAAE,EACvB,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,GAAG,IAAI,EACjD,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,GACpC,IAAI,CA+DN"}
1
+ {"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../../src/runtime/overlay.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAMhE,MAAM,MAAM,cAAc,GAAG;IAC3B,SAAS,EAAE,cAAc,CAAC;IAC1B,iBAAiB,EAAE,cAAc,CAAC;IAClC,WAAW,EAAE,cAAc,CAAC;IAC5B,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF,wBAAgB,aAAa,CAAC,IAAI,EAAE,QAAQ,GAAG,cAAc,CAgD5D;AAED,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,cAAc,EACzB,IAAI,EAAE,WAAW,GAChB,IAAI,CAQN;AAED,wBAAgB,yBAAyB,CACvC,iBAAiB,EAAE,cAAc,EACjC,IAAI,EAAE,WAAW,GAChB,IAAI,CAQN;AAED,wBAAgB,aAAa,CAAC,SAAS,EAAE,cAAc,GAAG,IAAI,CAE7D;AAED,wBAAgB,qBAAqB,CAAC,iBAAiB,EAAE,cAAc,GAAG,IAAI,CAE7E;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,OAAO,GAAG,WAAW,CAQvD;AAOD,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,cAAc,EACrB,OAAO,EAAE,YAAY,EAAE,EACvB,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,GAAG,IAAI,EACjD,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,GACpC,IAAI,CA+DN"}
@@ -2,13 +2,12 @@ const HIGHLIGHT_Z = 2147483646;
2
2
  const SELECTED_HIGHLIGHT_Z = 2147483643;
3
3
  const MARKER_Z = 2147483645;
4
4
  export function createOverlay(root) {
5
- console.log("[inspector] creating overlay");
6
5
  const selectedHighlight = root.createElement("div");
7
6
  selectedHighlight.setAttribute("data-abbox-inspector", "selected-highlight");
8
7
  Object.assign(selectedHighlight.style, {
9
8
  position: "fixed",
10
9
  pointerEvents: "none",
11
- border: "40px dashed #2563eb",
10
+ border: "2px dashed #2563eb",
12
11
  background: "rgba(37, 99, 235, 0.06)",
13
12
  borderRadius: "2px",
14
13
  zIndex: String(SELECTED_HIGHLIGHT_Z),
@@ -20,7 +19,7 @@ export function createOverlay(root) {
20
19
  Object.assign(highlight.style, {
21
20
  position: "fixed",
22
21
  pointerEvents: "none",
23
- border: "20px solid #2563eb",
22
+ border: "2px solid #2563eb",
24
23
  background: "rgba(37, 99, 235, 0.12)",
25
24
  borderRadius: "2px",
26
25
  zIndex: String(HIGHLIGHT_Z),
@@ -57,7 +56,6 @@ export function positionHighlight(highlight, rect) {
57
56
  });
58
57
  }
59
58
  export function positionSelectedHighlight(selectedHighlight, rect) {
60
- console.log("[inspector] positioning selected highlight at", rect);
61
59
  Object.assign(selectedHighlight.style, {
62
60
  display: "block",
63
61
  left: `${rect.x}px`,
@@ -117,7 +115,7 @@ export function renderChangeMarkers(layer, markers, resolveElement, onSelect) {
117
115
  background: marker.kind === "change-added"
118
116
  ? "#22c55e"
119
117
  : marker.kind === "change-modified"
120
- ? "#eab308"
118
+ ? "#f97316"
121
119
  : marker.kind === "mock"
122
120
  ? "#f59e0b"
123
121
  : "#ef4444",
@@ -142,8 +140,8 @@ export function renderChangeMarkers(layer, markers, resolveElement, onSelect) {
142
140
  : "0 0 0 1px rgba(0,0,0,0.2)";
143
141
  if (marker.pulse)
144
142
  ensurePulseStyle(layer.ownerDocument);
145
- dot.style.left = `${rect.x + rect.width - 8}px`;
146
- dot.style.top = `${rect.top - 4}px`;
143
+ dot.style.left = `${rect.x - 6}px`;
144
+ dot.style.top = `${rect.top - 6}px`;
147
145
  }
148
146
  }
149
147
  function ensurePulseStyle(doc) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abbox/inspector",
3
- "version": "0.4.11",
3
+ "version": "0.4.13",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },