@reekon-tools/boldr-utils 1.15.2 → 1.15.3

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.
@@ -13,7 +13,7 @@ const PLANE_GRID_COLOR = '#FFD1F8';
13
13
  const PLANE_GRID_OPACITY = 0.9;
14
14
  // Doc-space stroke widths (scale with zoom, like the drawn shapes).
15
15
  const PLANE_GRID_WIDTH = 2.5;
16
- const PLANE_OUTLINE_WIDTH = 4;
16
+ const PLANE_OUTLINE_WIDTH = 14;
17
17
  // Cross-tick half-length (doc units) marking the ends of a scale-mode
18
18
  // reference line, so it reads as "a measured span", not just a line.
19
19
  const REF_TICK_LEN = 18;
@@ -1,4 +1,4 @@
1
- import type { PlaneCalibration, PlaneCalibrationMode } from '../../../types/annotation.js';
1
+ import type { PlacedMeasurementRef, PlaneCalibration, PlaneCalibrationMode } from '../../../types/annotation.js';
2
2
  import type { Tool } from '../Tool.js';
3
3
  export interface PlaneToolOptions {
4
4
  id?: string;
@@ -7,6 +7,7 @@ export interface PlaneToolOptions {
7
7
  onPlaced?(plane: PlaneCalibration): void;
8
8
  onInvalidQuad?(): void;
9
9
  onExistingPlane?(): void;
10
+ onDimensionTileTap?(tile: PlacedMeasurementRef): void;
10
11
  minDragPx?: number;
11
12
  }
12
13
  export declare const createPlaneTool: (options: PlaneToolOptions) => Tool;
@@ -1,6 +1,7 @@
1
1
  import { DEFAULT_LAYER_ID } from '../../../types/annotation.js';
2
2
  import { isQuadConvexNonDegenerate, normalizeQuadOrder, planeEdgeLine, } from '../planeGeometry.js';
3
3
  import { linePosOf, recomputeAnchor, DEFAULT_LINE_POS, } from '../measurementGeometry.js';
4
+ import { stampTileDims } from '../stampLayout.js';
4
5
  import { FormulaColors } from '../../../theme/colors.js';
5
6
  // Screen-px grab radius for an existing plane's corner/endpoint handles while
6
7
  // the tool is active (matches the drawn handle affordance scale).
@@ -53,10 +54,10 @@ const buildDimensionTile = (doc, plane, edge) => {
53
54
  planeId: plane.id,
54
55
  planeEdge: edge,
55
56
  // The tile's line IS the plane edge PlaneElement already draws — style it
56
- // as the same cyan stroke so it disappears into the outline instead of
57
- // painting the default measurement blue on top of it.
57
+ // as the same purple stroke (and width) so it disappears into the outline
58
+ // instead of painting the default measurement blue on top of it.
58
59
  lineColor: PLANE_COLOR,
59
- lineWidth: 4,
60
+ lineWidth: 14,
60
61
  showLabel: true,
61
62
  showValue: true,
62
63
  createdAt: Date.now(),
@@ -192,6 +193,29 @@ export const createPlaneTool = (options) => {
192
193
  ctx.commit({ ops });
193
194
  options.onPlaced?.(plane);
194
195
  };
196
+ // Which committed-plane DIMENSION tile a tap landed on, if any — the tile
197
+ // BOX only (deliberately not the edge line, which spans the whole side and
198
+ // would turn every edge tap into value entry). Same footprint the overlay
199
+ // draws and the select tool grabs (stampTileDims + the ctx scale factors).
200
+ const hitDimensionTile = (ctx, world) => {
201
+ const plane = committedPlane(ctx.document);
202
+ if (!plane)
203
+ return null;
204
+ const zoom = ctx.viewport.state.zoom;
205
+ for (let i = ctx.document.placedMeasurements.length - 1; i >= 0; i--) {
206
+ const m = ctx.document.placedMeasurements[i];
207
+ if (m.planeId !== plane.id || !m.planeEdge)
208
+ continue;
209
+ const dims = stampTileDims(m, ctx.tileScaleFactor, ctx.tileViewportScale, ctx.headerTileScaleFactor, ctx.fileTileScaleFactor);
210
+ const halfW = (dims.width / 2 + 6) / zoom;
211
+ const halfH = (dims.height / 2 + 6) / zoom;
212
+ if (Math.abs(world.x - m.anchor.x) <= halfW &&
213
+ Math.abs(world.y - m.anchor.y) <= halfH) {
214
+ return m;
215
+ }
216
+ }
217
+ return null;
218
+ };
195
219
  // Which committed-plane handle a press landed on, if any.
196
220
  const hitHandle = (ctx, world) => {
197
221
  const plane = committedPlane(ctx.document);
@@ -300,9 +324,19 @@ export const createPlaneTool = (options) => {
300
324
  });
301
325
  return;
302
326
  }
303
- // Creation is blocked while a calibration exists (only its handles are
304
- // editable) the user deletes it first to re-mark.
327
+ // While a calibration exists, a TAP on one of its dimension tiles
328
+ // selects it and opens value entry (the host's onDimensionTileTap) —
329
+ // dimensions stay editable without leaving calibration mode. Any other
330
+ // attempt to mark new geometry is blocked: delete the plane first.
331
+ // (A real drag — scale mode with `moved` — is never a tile tap.)
305
332
  if (committedPlane(ctx.document)) {
333
+ const isTap = s.kind !== 'plane-scale-drawing' || !s.moved;
334
+ const tile = isTap ? hitDimensionTile(ctx, event.world) : null;
335
+ if (tile) {
336
+ ctx.setSelection({ ids: [tile.id] });
337
+ options.onDimensionTileTap?.(tile);
338
+ return;
339
+ }
306
340
  options.onExistingPlane?.();
307
341
  return;
308
342
  }
@@ -772,6 +772,10 @@ export const useAnnotationCanvasState = (props) => {
772
772
  // Build one remove op per selected element, dispatched by which
773
773
  // collection owns the id. A single multi-op commit makes the whole
774
774
  // deletion one undo step (inverse re-adds each element).
775
+ // Plane DIMENSION tiles (planeEdge) are exempt: they are the
776
+ // calibration's entry affordances and live and die with it
777
+ // (removePlane / the plane tool's replace flow) — their value is
778
+ // replaced by re-entering it, never by deleting the tile.
775
779
  const ops = [
776
780
  ...doc.strokes
777
781
  .filter((s) => idSet.has(s.id))
@@ -780,7 +784,7 @@ export const useAnnotationCanvasState = (props) => {
780
784
  .filter((s) => idSet.has(s.id))
781
785
  .map((s) => ({ op: 'removeShape', id: s.id })),
782
786
  ...doc.placedMeasurements
783
- .filter((m) => idSet.has(m.id))
787
+ .filter((m) => idSet.has(m.id) && !m.planeEdge)
784
788
  .map((m) => ({ op: 'removeMeasurement', id: m.id })),
785
789
  ];
786
790
  if (ops.length === 0)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reekon-tools/boldr-utils",
3
- "version": "1.15.2",
3
+ "version": "1.15.3",
4
4
  "description": "Shared utilities for formulas and measurement conversion used in Reekon apps",
5
5
  "author": "REEKON Tools",
6
6
  "license": "MIT",