@oyerinde/caliper 0.2.0 → 0.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/CHANGELOG.md CHANGED
@@ -2,6 +2,33 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [0.2.2] - 2026-03-05
6
+
7
+ ### Improved
8
+
9
+ - **Context Menu**: Swapped copy shortcuts. Right-click now copies the `data-caliper-agent-id`; `Shift + Right-Click` copies the full JSON fingerprint.
10
+
11
+ ### Fixed
12
+
13
+ - **Geometry Engine**: Fixed measurement breakout on sticky elements during scroll.
14
+ - **Logger**: Fixed `__DEV__` guard in production builds preventing `debug`, `info`, and `log` from appearing when enabled.
15
+ - **MCP Server**: Fixed `console.log` usage on startup to ensure `stdout` is reserved exclusively for the JSON-RPC protocol.
16
+
17
+ ## [0.2.1] - 2026-02-16
18
+
19
+ ### Refactored
20
+
21
+ - **Configuration Engine**: Renamed `OverlayConfig` to `CaliperConfig` to reflect its expanded scope.
22
+ - **Bridge Decoupling**: Moved `bridge` configuration out of the core config type. It is now exclusively a plugin concern, with specialized `IIFEConfig` handling for CDN/script-tag users.
23
+
24
+ ### Added
25
+
26
+ - **Agent Bridge Serialization**: Introduced `onStateChangeGlobal` to allow string-based callback names in `data-config` for IIFE/CDN environments.
27
+
28
+ ### Fixed
29
+
30
+ - **Boundary Box Snapping**: Fixed boxes snapping to (0,0) by retaining last known position for detached or animating elements.
31
+
5
32
  ## [0.2.0] - 2026-02-12
6
33
 
7
34
  ### Added
package/README.md CHANGED
@@ -1,6 +1,5 @@
1
1
  <img src="https://raw.githubusercontent.com/oyerindedaniel/caliper/main/apps/web/public/caliper_logo.svg" width="144" alt="Caliper Logo" style="margin-bottom: 24px;" />
2
2
 
3
- [![Unpkg Bundle Size](https://img.shields.io/bundlephobia/minzip/@oyerinde/caliper?style=flat-square&color=black&labelColor=black)](https://bundlephobia.com/package/@oyerinde/caliper)
4
3
  [![NPM Version](https://img.shields.io/npm/v/@oyerinde/caliper?style=flat-square&color=black&labelColor=black)](https://www.npmjs.com/package/@oyerinde/caliper)
5
4
 
6
5
  **Essential tooling for detail-obsessed design engineers.**
@@ -183,7 +182,7 @@ const caliper = init();
183
182
  caliper.use(
184
183
  CaliperBridge({
185
184
  enabled: true,
186
- wsUrl: "ws://localhost:9876",
185
+ wsPort: 9876,
187
186
  })
188
187
  );
189
188
  ```
@@ -263,10 +262,6 @@ init({
263
262
  enabled: true, // Smooth hover box
264
263
  lerpFactor: 0.25, // Fluidity (low = slower)
265
264
  },
266
- bridge: {
267
- enabled: true, // Connect to AI Agents
268
- wsPort: 9876, // Port for MCP relay
269
- },
270
265
  });
271
266
  ```
272
267
 
@@ -324,9 +319,6 @@ For AI agents to reliably rediscover elements across re-renders (like HMR), we r
324
319
 
325
320
  This project is licensed under the **MIT License**.
326
321
 
327
- - **Allowed**: Personal and commercial use, modification, and distribution.
328
- - **Open**: Completely permissive with no restrictions on derivative works or competition.
329
-
330
322
  ---
331
323
 
332
324
  ## Author & Acknowledgement 👤
package/dist/bridge.cjs CHANGED
@@ -1,50 +1,50 @@
1
1
  'use strict';
2
2
 
3
- var chunk3W2YKDGV_cjs = require('./chunk-3W2YKDGV.cjs');
3
+ var chunk2SVFU7M3_cjs = require('./chunk-2SVFU7M3.cjs');
4
4
 
5
5
 
6
6
 
7
7
  Object.defineProperty(exports, "CALIPER_METHODS", {
8
8
  enumerable: true,
9
- get: function () { return chunk3W2YKDGV_cjs.CALIPER_METHODS; }
9
+ get: function () { return chunk2SVFU7M3_cjs.CALIPER_METHODS; }
10
10
  });
11
11
  Object.defineProperty(exports, "CaliperActionResultSchema", {
12
12
  enumerable: true,
13
- get: function () { return chunk3W2YKDGV_cjs.CaliperActionResultSchema; }
13
+ get: function () { return chunk2SVFU7M3_cjs.CaliperActionResultSchema; }
14
14
  });
15
15
  Object.defineProperty(exports, "CaliperAgentStateSchema", {
16
16
  enumerable: true,
17
- get: function () { return chunk3W2YKDGV_cjs.CaliperAgentStateSchema; }
17
+ get: function () { return chunk2SVFU7M3_cjs.CaliperAgentStateSchema; }
18
18
  });
19
19
  Object.defineProperty(exports, "CaliperBridge", {
20
20
  enumerable: true,
21
- get: function () { return chunk3W2YKDGV_cjs.CaliperBridge; }
21
+ get: function () { return chunk2SVFU7M3_cjs.CaliperBridge; }
22
22
  });
23
23
  Object.defineProperty(exports, "CaliperGetContextPayloadSchema", {
24
24
  enumerable: true,
25
- get: function () { return chunk3W2YKDGV_cjs.CaliperGetContextPayloadSchema; }
25
+ get: function () { return chunk2SVFU7M3_cjs.CaliperGetContextPayloadSchema; }
26
26
  });
27
27
  Object.defineProperty(exports, "CaliperInspectPayloadSchema", {
28
28
  enumerable: true,
29
- get: function () { return chunk3W2YKDGV_cjs.CaliperInspectPayloadSchema; }
29
+ get: function () { return chunk2SVFU7M3_cjs.CaliperInspectPayloadSchema; }
30
30
  });
31
31
  Object.defineProperty(exports, "CaliperMeasurePayloadSchema", {
32
32
  enumerable: true,
33
- get: function () { return chunk3W2YKDGV_cjs.CaliperMeasurePayloadSchema; }
33
+ get: function () { return chunk2SVFU7M3_cjs.CaliperMeasurePayloadSchema; }
34
34
  });
35
35
  Object.defineProperty(exports, "CaliperSelectPayloadSchema", {
36
36
  enumerable: true,
37
- get: function () { return chunk3W2YKDGV_cjs.CaliperSelectPayloadSchema; }
37
+ get: function () { return chunk2SVFU7M3_cjs.CaliperSelectPayloadSchema; }
38
38
  });
39
39
  Object.defineProperty(exports, "CaliperWalkAndMeasurePayloadSchema", {
40
40
  enumerable: true,
41
- get: function () { return chunk3W2YKDGV_cjs.CaliperWalkAndMeasurePayloadSchema; }
41
+ get: function () { return chunk2SVFU7M3_cjs.CaliperWalkAndMeasurePayloadSchema; }
42
42
  });
43
43
  Object.defineProperty(exports, "CaliperWalkDomPayloadSchema", {
44
44
  enumerable: true,
45
- get: function () { return chunk3W2YKDGV_cjs.CaliperWalkDomPayloadSchema; }
45
+ get: function () { return chunk2SVFU7M3_cjs.CaliperWalkDomPayloadSchema; }
46
46
  });
47
47
  Object.defineProperty(exports, "dispatchCaliperIntent", {
48
48
  enumerable: true,
49
- get: function () { return chunk3W2YKDGV_cjs.dispatchCaliperIntent; }
49
+ get: function () { return chunk2SVFU7M3_cjs.dispatchCaliperIntent; }
50
50
  });
package/dist/bridge.d.cts CHANGED
@@ -8,6 +8,8 @@ declare interface AgentBridgeConfig {
8
8
  wsPort?: number;
9
9
  /** Callback for agent state changes */
10
10
  onStateChange?: (state: CaliperAgentState) => void;
11
+ /** Name of a global window function to call on state changes (IIFE/CDN-safe, JSON-serializable) */
12
+ onStateChangeGlobal?: string;
11
13
  }
12
14
 
13
15
  declare interface CalculatorIntegration {
@@ -882,7 +884,7 @@ export declare const CaliperAgentStateSchema: z.ZodObject<{
882
884
  * When installed, this plugin:
883
885
  * 1. Starts a local WebSocket server (or connects to one) to receive agent commands.
884
886
  * 2. Exposes `window.dispatchCaliperIntent` for manual/in-page agentic calls.
885
- * 3. Syncs the overlay state (camera, selection, measurements) back to the agent.
887
+ * 3. Syncs the overlay state (selection, measurements) back to the agent.
886
888
  *
887
889
  * @example
888
890
  * ```ts
package/dist/bridge.d.ts CHANGED
@@ -8,6 +8,8 @@ declare interface AgentBridgeConfig {
8
8
  wsPort?: number;
9
9
  /** Callback for agent state changes */
10
10
  onStateChange?: (state: CaliperAgentState) => void;
11
+ /** Name of a global window function to call on state changes (IIFE/CDN-safe, JSON-serializable) */
12
+ onStateChangeGlobal?: string;
11
13
  }
12
14
 
13
15
  declare interface CalculatorIntegration {
@@ -882,7 +884,7 @@ export declare const CaliperAgentStateSchema: z.ZodObject<{
882
884
  * When installed, this plugin:
883
885
  * 1. Starts a local WebSocket server (or connects to one) to receive agent commands.
884
886
  * 2. Exposes `window.dispatchCaliperIntent` for manual/in-page agentic calls.
885
- * 3. Syncs the overlay state (camera, selection, measurements) back to the agent.
887
+ * 3. Syncs the overlay state (selection, measurements) back to the agent.
886
888
  *
887
889
  * @example
888
890
  * ```ts
package/dist/bridge.js CHANGED
@@ -1 +1 @@
1
- export { CALIPER_METHODS, CaliperActionResultSchema, CaliperAgentStateSchema, CaliperBridge, CaliperGetContextPayloadSchema, CaliperInspectPayloadSchema, CaliperMeasurePayloadSchema, CaliperSelectPayloadSchema, CaliperWalkAndMeasurePayloadSchema, CaliperWalkDomPayloadSchema, dispatchCaliperIntent } from './chunk-ACV6FK43.js';
1
+ export { CALIPER_METHODS, CaliperActionResultSchema, CaliperAgentStateSchema, CaliperBridge, CaliperGetContextPayloadSchema, CaliperInspectPayloadSchema, CaliperMeasurePayloadSchema, CaliperSelectPayloadSchema, CaliperWalkAndMeasurePayloadSchema, CaliperWalkDomPayloadSchema, dispatchCaliperIntent } from './chunk-PRUCSUJA.js';
@@ -230,7 +230,6 @@ var WalkOptionsSchema = zod.z.object({
230
230
  minElementSize: zod.z.number().optional(),
231
231
  ignoreSelectors: zod.z.array(zod.z.string()).optional()
232
232
  });
233
- var JSONRPCResultResponseSchema = types_js.JSONRPCResultResponseSchema;
234
233
  var JSONRPCErrorResponseSchema = types_js.JSONRPCErrorResponseSchema;
235
234
  var ViewportSchema = zod.z.object({
236
235
  width: zod.z.number(),
@@ -290,8 +289,20 @@ var SourceHintsSchema = zod.z.object({
290
289
  tagName: zod.z.string()
291
290
  });
292
291
  var CaliperActionResultSchema = zod.z.union([
293
- zod.z.object({ success: zod.z.literal(true), method: zod.z.literal(CALIPER_METHODS.SELECT), selector: zod.z.string(), selection: SelectionMetadataSchema, timestamp: zod.z.number() }),
294
- zod.z.object({ success: zod.z.literal(true), method: zod.z.literal(CALIPER_METHODS.MEASURE), selector: zod.z.string(), measurement: MeasurementResultSchema, timestamp: zod.z.number() }),
292
+ zod.z.object({
293
+ success: zod.z.literal(true),
294
+ method: zod.z.literal(CALIPER_METHODS.SELECT),
295
+ selector: zod.z.string(),
296
+ selection: SelectionMetadataSchema,
297
+ timestamp: zod.z.number()
298
+ }),
299
+ zod.z.object({
300
+ success: zod.z.literal(true),
301
+ method: zod.z.literal(CALIPER_METHODS.MEASURE),
302
+ selector: zod.z.string(),
303
+ measurement: MeasurementResultSchema,
304
+ timestamp: zod.z.number()
305
+ }),
295
306
  zod.z.object({
296
307
  success: zod.z.literal(true),
297
308
  method: zod.z.literal(CALIPER_METHODS.INSPECT),
@@ -312,8 +323,16 @@ var CaliperActionResultSchema = zod.z.union([
312
323
  sourceHints: SourceHintsSchema.optional(),
313
324
  timestamp: zod.z.number()
314
325
  }),
315
- zod.z.object({ success: zod.z.literal(true), method: zod.z.literal(CALIPER_METHODS.FREEZE), timestamp: zod.z.number() }),
316
- zod.z.object({ success: zod.z.literal(true), method: zod.z.literal(CALIPER_METHODS.CLEAR), timestamp: zod.z.number() }),
326
+ zod.z.object({
327
+ success: zod.z.literal(true),
328
+ method: zod.z.literal(CALIPER_METHODS.FREEZE),
329
+ timestamp: zod.z.number()
330
+ }),
331
+ zod.z.object({
332
+ success: zod.z.literal(true),
333
+ method: zod.z.literal(CALIPER_METHODS.CLEAR),
334
+ timestamp: zod.z.number()
335
+ }),
317
336
  zod.z.object({
318
337
  success: zod.z.literal(true),
319
338
  method: zod.z.literal(CALIPER_METHODS.WALK_DOM),
@@ -400,11 +419,7 @@ var CaliperNotificationSchema = zod.z.union([
400
419
  params: CaliperAgentStateSchema
401
420
  })
402
421
  ]);
403
- zod.z.union([
404
- CaliperResponseSchema,
405
- CaliperNotificationSchema,
406
- JSONRPCResultResponseSchema
407
- ]);
422
+ zod.z.union([CaliperResponseSchema, CaliperNotificationSchema]);
408
423
  var CaliperSelectPayloadSchema = zod.z.object({
409
424
  selector: zod.z.string()
410
425
  });
@@ -1362,10 +1377,12 @@ var Logger = class {
1362
1377
  isGlobalEnabled = enabled;
1363
1378
  }
1364
1379
  debug(...args) {
1365
- return;
1380
+ if (!isGlobalEnabled) return;
1381
+ console.debug(this.prefix, ...args);
1366
1382
  }
1367
1383
  info(...args) {
1368
- return;
1384
+ if (!isGlobalEnabled) return;
1385
+ console.info(this.prefix, ...args);
1369
1386
  }
1370
1387
  warn(...args) {
1371
1388
  if (!isGlobalEnabled) return;
@@ -1376,7 +1393,8 @@ var Logger = class {
1376
1393
  console.error(this.prefix, ...args);
1377
1394
  }
1378
1395
  log(...args) {
1379
- return;
1396
+ if (!isGlobalEnabled) return;
1397
+ console.log(this.prefix, ...args);
1380
1398
  }
1381
1399
  };
1382
1400
  new Logger({ prefix: "Caliper" });
@@ -15074,7 +15092,7 @@ var JSONRPCNotificationSchema = object({
15074
15092
  jsonrpc: literal(JSONRPC_VERSION),
15075
15093
  ...NotificationSchema.shape
15076
15094
  }).strict();
15077
- var JSONRPCResultResponseSchema2 = object({
15095
+ var JSONRPCResultResponseSchema = object({
15078
15096
  jsonrpc: literal(JSONRPC_VERSION),
15079
15097
  id: RequestIdSchema,
15080
15098
  result: ResultSchema
@@ -15111,10 +15129,10 @@ var JSONRPCErrorResponseSchema2 = object({
15111
15129
  union([
15112
15130
  JSONRPCRequestSchema,
15113
15131
  JSONRPCNotificationSchema,
15114
- JSONRPCResultResponseSchema2,
15132
+ JSONRPCResultResponseSchema,
15115
15133
  JSONRPCErrorResponseSchema2
15116
15134
  ]);
15117
- union([JSONRPCResultResponseSchema2, JSONRPCErrorResponseSchema2]);
15135
+ union([JSONRPCResultResponseSchema, JSONRPCErrorResponseSchema2]);
15118
15136
  var EmptyResultSchema = ResultSchema.strict();
15119
15137
  var CancelledNotificationParamsSchema = NotificationsParamsSchema.extend({
15120
15138
  /**
@@ -16678,7 +16696,7 @@ var WalkOptionsSchema2 = external_exports.object({
16678
16696
  });
16679
16697
  var JSONRPCRequestSchema2 = JSONRPCRequestSchema;
16680
16698
  var JSONRPCNotificationSchema2 = JSONRPCNotificationSchema;
16681
- var JSONRPCResultResponseSchema22 = JSONRPCResultResponseSchema2;
16699
+ var JSONRPCResultResponseSchema2 = JSONRPCResultResponseSchema;
16682
16700
  var JSONRPCErrorResponseSchema22 = JSONRPCErrorResponseSchema2;
16683
16701
  var ViewportSchema2 = external_exports.object({
16684
16702
  width: external_exports.number(),
@@ -16738,8 +16756,20 @@ var SourceHintsSchema2 = external_exports.object({
16738
16756
  tagName: external_exports.string()
16739
16757
  });
16740
16758
  var CaliperActionResultSchema2 = external_exports.union([
16741
- external_exports.object({ success: external_exports.literal(true), method: external_exports.literal(CALIPER_METHODS2.SELECT), selector: external_exports.string(), selection: SelectionMetadataSchema2, timestamp: external_exports.number() }),
16742
- external_exports.object({ success: external_exports.literal(true), method: external_exports.literal(CALIPER_METHODS2.MEASURE), selector: external_exports.string(), measurement: MeasurementResultSchema2, timestamp: external_exports.number() }),
16759
+ external_exports.object({
16760
+ success: external_exports.literal(true),
16761
+ method: external_exports.literal(CALIPER_METHODS2.SELECT),
16762
+ selector: external_exports.string(),
16763
+ selection: SelectionMetadataSchema2,
16764
+ timestamp: external_exports.number()
16765
+ }),
16766
+ external_exports.object({
16767
+ success: external_exports.literal(true),
16768
+ method: external_exports.literal(CALIPER_METHODS2.MEASURE),
16769
+ selector: external_exports.string(),
16770
+ measurement: MeasurementResultSchema2,
16771
+ timestamp: external_exports.number()
16772
+ }),
16743
16773
  external_exports.object({
16744
16774
  success: external_exports.literal(true),
16745
16775
  method: external_exports.literal(CALIPER_METHODS2.INSPECT),
@@ -16760,8 +16790,16 @@ var CaliperActionResultSchema2 = external_exports.union([
16760
16790
  sourceHints: SourceHintsSchema2.optional(),
16761
16791
  timestamp: external_exports.number()
16762
16792
  }),
16763
- external_exports.object({ success: external_exports.literal(true), method: external_exports.literal(CALIPER_METHODS2.FREEZE), timestamp: external_exports.number() }),
16764
- external_exports.object({ success: external_exports.literal(true), method: external_exports.literal(CALIPER_METHODS2.CLEAR), timestamp: external_exports.number() }),
16793
+ external_exports.object({
16794
+ success: external_exports.literal(true),
16795
+ method: external_exports.literal(CALIPER_METHODS2.FREEZE),
16796
+ timestamp: external_exports.number()
16797
+ }),
16798
+ external_exports.object({
16799
+ success: external_exports.literal(true),
16800
+ method: external_exports.literal(CALIPER_METHODS2.CLEAR),
16801
+ timestamp: external_exports.number()
16802
+ }),
16765
16803
  external_exports.object({
16766
16804
  success: external_exports.literal(true),
16767
16805
  method: external_exports.literal(CALIPER_METHODS2.WALK_DOM),
@@ -16821,13 +16859,21 @@ var RpcFactory = class {
16821
16859
  return JSONRPCRequestSchema2.parse({ jsonrpc: "2.0", method, params, id });
16822
16860
  }
16823
16861
  static response(id, result) {
16824
- return JSONRPCResultResponseSchema22.parse({ jsonrpc: "2.0", id, result });
16862
+ return JSONRPCResultResponseSchema2.parse({ jsonrpc: "2.0", id, result });
16825
16863
  }
16826
16864
  static error(id, code, message, data) {
16827
- return JSONRPCErrorResponseSchema22.parse({ jsonrpc: "2.0", id, error: { code, message, data } });
16865
+ return JSONRPCErrorResponseSchema22.parse({
16866
+ jsonrpc: "2.0",
16867
+ id,
16868
+ error: { code, message, data }
16869
+ });
16828
16870
  }
16829
16871
  static notification(method, params) {
16830
- return JSONRPCNotificationSchema2.parse({ jsonrpc: "2.0", method, params });
16872
+ return JSONRPCNotificationSchema2.parse({
16873
+ jsonrpc: "2.0",
16874
+ method,
16875
+ params
16876
+ });
16831
16877
  }
16832
16878
  };
16833
16879
  var CaliperResponseSchema2 = external_exports.union([
@@ -16862,11 +16908,7 @@ var CaliperNotificationSchema2 = external_exports.union([
16862
16908
  params: CaliperAgentStateSchema2
16863
16909
  })
16864
16910
  ]);
16865
- external_exports.union([
16866
- CaliperResponseSchema2,
16867
- CaliperNotificationSchema2,
16868
- JSONRPCResultResponseSchema22
16869
- ]);
16911
+ external_exports.union([CaliperResponseSchema2, CaliperNotificationSchema2]);
16870
16912
  external_exports.object({
16871
16913
  selector: external_exports.string()
16872
16914
  });
@@ -18564,6 +18606,12 @@ function CaliperBridge(config2) {
18564
18606
  const disposeSync = initStateSync(stateStore, systems, (state) => {
18565
18607
  wsBridge.sendStateUpdate(state);
18566
18608
  config2.onStateChange?.(state);
18609
+ if (config2.onStateChangeGlobal) {
18610
+ const globalCallback = window[config2.onStateChangeGlobal];
18611
+ if (typeof globalCallback === "function") {
18612
+ globalCallback(state);
18613
+ }
18614
+ }
18567
18615
  });
18568
18616
  window.dispatchCaliperIntent = async (intent) => {
18569
18617
  if (!intentHandler) {
@@ -2852,8 +2852,7 @@ function getConfig() {
2852
2852
  ...parsed,
2853
2853
  theme: { ...windowConfig.theme, ...parsed.theme },
2854
2854
  commands: { ...windowConfig.commands, ...parsed.commands },
2855
- animation: { ...windowConfig.animation, ...parsed.animation },
2856
- bridge: { ...windowConfig.bridge, ...parsed.bridge }
2855
+ animation: { ...windowConfig.animation, ...parsed.animation }
2857
2856
  };
2858
2857
  } catch (e) {
2859
2858
  console.warn("[CALIPER] Failed to parse data-config attribute", e);
@@ -3033,10 +3032,12 @@ var Logger = class {
3033
3032
  isGlobalEnabled = enabled;
3034
3033
  }
3035
3034
  debug(...args) {
3036
- return;
3035
+ if (!isGlobalEnabled) return;
3036
+ console.debug(this.prefix, ...args);
3037
3037
  }
3038
3038
  info(...args) {
3039
- return;
3039
+ if (!isGlobalEnabled) return;
3040
+ console.info(this.prefix, ...args);
3040
3041
  }
3041
3042
  warn(...args) {
3042
3043
  if (!isGlobalEnabled) return;
@@ -3047,7 +3048,8 @@ var Logger = class {
3047
3048
  console.error(this.prefix, ...args);
3048
3049
  }
3049
3050
  log(...args) {
3050
- return;
3051
+ if (!isGlobalEnabled) return;
3052
+ console.log(this.prefix, ...args);
3051
3053
  }
3052
3054
  };
3053
3055
  var logger = new Logger({ prefix: "Caliper" });
@@ -3436,11 +3438,11 @@ function MeasurementLinesWithCalculator(props) {
3436
3438
  };
3437
3439
  }
3438
3440
  if (line.type === "top" || line.type === "bottom") {
3439
- if (line.startSync === "primary") end.x = start.x;
3440
- else start.x = end.x;
3441
+ if (line.type === "top") start.x = end.x;
3442
+ else end.x = start.x;
3441
3443
  } else if (line.type === "left" || line.type === "right") {
3442
- if (line.startSync === "primary") end.y = start.y;
3443
- else start.y = end.y;
3444
+ if (line.type === "left") start.y = end.y;
3445
+ else end.y = start.y;
3444
3446
  }
3445
3447
  let liveValue = 0;
3446
3448
  if (line.type === "top" || line.type === "bottom") {
@@ -3538,11 +3540,11 @@ function MeasurementLabels(props) {
3538
3540
  };
3539
3541
  }
3540
3542
  if (line.type === "top" || line.type === "bottom") {
3541
- if (line.startSync === "primary") end.x = start.x;
3542
- else start.x = end.x;
3543
+ if (line.type === "top") start.x = end.x;
3544
+ else end.x = start.x;
3543
3545
  } else if (line.type === "left" || line.type === "right") {
3544
- if (line.startSync === "primary") end.y = start.y;
3545
- else start.y = end.y;
3546
+ if (line.type === "left") start.y = end.y;
3547
+ else end.y = start.y;
3546
3548
  }
3547
3549
  const naturalX = (start.x + end.x) / 2;
3548
3550
  const naturalY = (start.y + end.y) / 2;
@@ -3757,16 +3759,27 @@ function BoundaryBoxes(props) {
3757
3759
  height: next.height
3758
3760
  };
3759
3761
  };
3760
- const liveSelectionTarget = createMemo(() => {
3762
+ const isDegenerate = (geo) => geo !== null && geo.width === 0 && geo.height === 0;
3763
+ const liveSelectionTarget = createMemo((prev) => {
3761
3764
  props.viewport.version;
3762
- return getLiveGeometry(props.metadata.rect, props.metadata.scrollHierarchy, props.metadata.position, props.metadata.stickyConfig, props.metadata.initialWindowX, props.metadata.initialWindowY);
3763
- });
3764
- const liveSecondaryTarget = createMemo(() => {
3765
+ if (prev && props.metadata.element && !document.contains(props.metadata.element)) {
3766
+ return prev;
3767
+ }
3768
+ const geo = getLiveGeometry(props.metadata.rect, props.metadata.scrollHierarchy, props.metadata.position, props.metadata.stickyConfig, props.metadata.initialWindowX, props.metadata.initialWindowY);
3769
+ if (isDegenerate(geo)) return prev;
3770
+ return geo;
3771
+ }, null);
3772
+ const liveSecondaryTarget = createMemo((prev) => {
3765
3773
  props.viewport.version;
3766
3774
  const res = props.result;
3767
3775
  if (!(props.isActivatePressed || props.isFrozen) || !res) return null;
3768
- return getLiveGeometry(res.secondary, res.secondaryHierarchy, res.secondaryPosition, res.secondarySticky, res.secondaryWinX, res.secondaryWinY);
3769
- });
3776
+ if (prev && res.secondaryElement && !document.contains(res.secondaryElement)) {
3777
+ return prev;
3778
+ }
3779
+ const geo = getLiveGeometry(res.secondary, res.secondaryHierarchy, res.secondaryPosition, res.secondarySticky, res.secondaryWinX, res.secondaryWinY);
3780
+ if (isDegenerate(geo)) return prev;
3781
+ return geo;
3782
+ }, null);
3770
3783
  createEffect(on([liveSelectionTarget, liveSecondaryTarget, () => props.animation.lerpFactor, () => props.metadata.element], ([selection, secondary, factor, element]) => {
3771
3784
  if (!selection) {
3772
3785
  setAnchor(null);
@@ -5095,27 +5108,48 @@ function Root(config) {
5095
5108
  contextEvent.preventDefault();
5096
5109
  contextEvent.stopImmediatePropagation();
5097
5110
  let clipboardContent = "";
5098
- if (contextEvent.shiftKey && selectedElement) {
5099
- clipboardContent = selectedElement.getAttribute("data-caliper-agent-id") || "";
5100
- } else if (measurementResult && system && selectionSystem) {
5101
- const primaryElement = selectionSystem.getSelected();
5102
- const secondaryElement = system.getSecondaryElement();
5103
- if (primaryElement && secondaryElement) {
5104
- clipboardContent = JSON.stringify({
5105
- primary: buildSelectorInfo(primaryElement, selectionMetadata()),
5106
- secondary: buildSelectorInfo(secondaryElement, {
5107
- rect: measurementResult.secondary,
5108
- scrollHierarchy: measurementResult.secondaryHierarchy,
5109
- position: measurementResult.secondaryPosition,
5110
- stickyConfig: measurementResult.secondarySticky,
5111
- initialWindowX: measurementResult.secondaryWinX,
5112
- initialWindowY: measurementResult.secondaryWinY,
5113
- hasContainingBlock: measurementResult.secondaryHasContainingBlock
5114
- })
5115
- });
5111
+ if (contextEvent.shiftKey) {
5112
+ if (measurementResult && system && selectionSystem) {
5113
+ const primaryElement = selectionSystem.getSelected();
5114
+ const secondaryElement = system.getSecondaryElement();
5115
+ if (primaryElement && secondaryElement) {
5116
+ clipboardContent = JSON.stringify({
5117
+ primary: buildSelectorInfo(primaryElement, selectionMetadata()),
5118
+ secondary: buildSelectorInfo(secondaryElement, {
5119
+ rect: measurementResult.secondary,
5120
+ scrollHierarchy: measurementResult.secondaryHierarchy,
5121
+ position: measurementResult.secondaryPosition,
5122
+ stickyConfig: measurementResult.secondarySticky,
5123
+ initialWindowX: measurementResult.secondaryWinX,
5124
+ initialWindowY: measurementResult.secondaryWinY,
5125
+ hasContainingBlock: measurementResult.secondaryHasContainingBlock
5126
+ })
5127
+ });
5128
+ }
5129
+ } else if (selectedElement) {
5130
+ clipboardContent = JSON.stringify(buildSelectorInfo(selectedElement, selectionMetadata()));
5131
+ }
5132
+ } else {
5133
+ const ensureAgentId = (el) => {
5134
+ let id = el.getAttribute("data-caliper-agent-id");
5135
+ if (!id) {
5136
+ id = generateId("caliper");
5137
+ el.setAttribute("data-caliper-agent-id", id);
5138
+ }
5139
+ return id;
5140
+ };
5141
+ if (measurementResult && system && selectionSystem) {
5142
+ const primaryElement = selectionSystem.getSelected();
5143
+ const secondaryElement = system.getSecondaryElement();
5144
+ if (primaryElement && secondaryElement) {
5145
+ clipboardContent = JSON.stringify({
5146
+ primary: ensureAgentId(primaryElement),
5147
+ secondary: ensureAgentId(secondaryElement)
5148
+ });
5149
+ }
5150
+ } else if (selectedElement) {
5151
+ clipboardContent = ensureAgentId(selectedElement);
5116
5152
  }
5117
- } else if (selectedElement) {
5118
- clipboardContent = JSON.stringify(buildSelectorInfo(selectedElement, selectionMetadata()));
5119
5153
  }
5120
5154
  if (clipboardContent) {
5121
5155
  navigator.clipboard.writeText(clipboardContent).then(() => {
@@ -5172,12 +5206,13 @@ function Root(config) {
5172
5206
  if (selectedElement) {
5173
5207
  const hoveredElement = getTopElementAtPoint(e.clientX, e.clientY);
5174
5208
  const isAncestor = hoveredElement && lastHoveredElement && hoveredElement.contains(lastHoveredElement) && hoveredElement !== lastHoveredElement;
5209
+ const lastHoveredDetached = lastHoveredElement && !document.contains(lastHoveredElement);
5175
5210
  if (isAlt) {
5176
5211
  if (system) {
5177
5212
  measureDelegate.execute(!!isAncestor, selectedElement, cursorPoint, hoveredElement);
5178
5213
  }
5179
5214
  } else if (state !== "FROZEN") {
5180
- if (hoveredElement) {
5215
+ if (hoveredElement && !lastHoveredDetached) {
5181
5216
  selectionDelegate.execute(!!isAncestor, hoveredElement);
5182
5217
  }
5183
5218
  }
@@ -5555,14 +5590,14 @@ function Root(config) {
5555
5590
  let secondaryChanged = false;
5556
5591
  const runUpdates2 = () => {
5557
5592
  if (sentinelResized || primaryChanged) {
5558
- if (observedPrimary) {
5593
+ if (observedPrimary && document.contains(observedPrimary)) {
5559
5594
  const rect = observedPrimary.getBoundingClientRect();
5560
5595
  selectionSystem?.updateRect(rect);
5561
5596
  if (system) system.updatePrimaryRect(rect);
5562
5597
  }
5563
5598
  }
5564
5599
  if (sentinelResized || secondaryChanged) {
5565
- if (observedSecondary) {
5600
+ if (observedSecondary && document.contains(observedSecondary)) {
5566
5601
  const rect = observedSecondary.getBoundingClientRect();
5567
5602
  system?.updateSecondaryRect(rect);
5568
5603
  }
@@ -5877,12 +5912,12 @@ function createOverlay(config) {
5877
5912
  return instance;
5878
5913
  }
5879
5914
  if (IS_BROWSER2) {
5880
- showVersionInfo("0.2.0").catch(() => {
5915
+ showVersionInfo("0.2.2").catch(() => {
5881
5916
  });
5882
5917
  }
5883
5918
 
5884
5919
  // src/index.ts
5885
- var VERSION = "0.2.0";
5920
+ var VERSION = "0.2.2";
5886
5921
 
5887
5922
  exports.VERSION = VERSION;
5888
5923
  exports.caliperProps = caliperProps;