@orbat-mapper/tactical-draw 0.2.0-alpha.39 → 0.2.0-alpha.40

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.d.mts CHANGED
@@ -685,8 +685,18 @@ interface EditSession {
685
685
  * and on `close()`. A no-op for measures with no pixel-denominated size. The
686
686
  * in-flight preview is unaffected (it renders from the working options), so a
687
687
  * screen-locked symbol stays screen-locked until commit.
688
- */
689
- setSizeAnchor(anchor: SizeAnchor): void;
688
+ *
689
+ * `options` shallow-merges a size-option patch in the *same* mutation, as
690
+ * [[setOptions]] would. Changing a measure's size mode means moving its value
691
+ * between the pixel and meter halves of a size pair *and* re-anchoring, and
692
+ * the halves are only meaningful together: options carrying a pixel size
693
+ * under a `"ground"` anchor bake that size away on commit, so a host that
694
+ * emitted the two as separate mutations would leave an undo step parked on a
695
+ * state whose committed size mode contradicts its own options. Passed here
696
+ * they are one change event and one history entry, which undo cannot land
697
+ * inside.
698
+ */
699
+ setSizeAnchor(anchor: SizeAnchor, options?: ControlMeasure["options"]): void;
690
700
  /** Shallow-merge per-measure style into the live working copy. */
691
701
  setStyle(partial: ControlMeasureStyle): void;
692
702
  /**
package/dist/index.mjs CHANGED
@@ -4322,11 +4322,24 @@ function runEdit(opts) {
4322
4322
  * and emits a change so hosts see the re-anchored measure. The working render
4323
4323
  * is unaffected — it renders from `workingOptions`, which still carry the
4324
4324
  * pixel size, so the in-flight symbol stays screen-locked until commit.
4325
+ *
4326
+ * An `options` patch rides along in the same mutation, merged as
4327
+ * [[setOptions]] merges. That pairing is the point: a size *mode* switch
4328
+ * moves the value between a size pair's pixel and meter halves and re-anchors
4329
+ * the measure, and only the combination is coherent — pixel options under a
4330
+ * `"ground"` anchor bake back to meters on commit. As two mutations they
4331
+ * would be two history entries with exactly that incoherent state between
4332
+ * them, reachable by a single undo.
4325
4333
  */
4326
- function setSizeAnchor(next) {
4327
- if (ctx.settled || sizeAnchor === next) return;
4328
- const previousPoints = workingPoints.map((p) => [...p]);
4334
+ function setSizeAnchor(next, options) {
4335
+ if (ctx.settled) return;
4329
4336
  const previousOptions = { ...workingOptions ?? {} };
4337
+ const nextOptions = options ? {
4338
+ ...previousOptions,
4339
+ ...options
4340
+ } : void 0;
4341
+ if (sizeAnchor === next && (!nextOptions || jsonEqual(nextOptions, previousOptions))) return;
4342
+ const previousPoints = workingPoints.map((p) => [...p]);
4330
4343
  const previousStyle = currentStyle;
4331
4344
  const previousNonGeometryDirty = nonGeometryDirty;
4332
4345
  const previousSizeAnchor = sizeAnchor;
@@ -4335,10 +4348,19 @@ function runEdit(opts) {
4335
4348
  const previousProperties = snapshotProperties();
4336
4349
  const previousRendered = rebuildRendered();
4337
4350
  sizeAnchor = next;
4338
- const currentRendered = rebuildRendered();
4351
+ if (nextOptions) replaceWorkingOptions(nextOptions);
4352
+ let currentRendered;
4353
+ try {
4354
+ currentRendered = rebuildRendered();
4355
+ } catch (err) {
4356
+ sizeAnchor = previousSizeAnchor;
4357
+ replaceWorkingOptions(previousOptions);
4358
+ throw err;
4359
+ }
4360
+ if (nextOptions) renderWorkingGraphicAndHandles();
4339
4361
  nonGeometryDirty = true;
4340
4362
  dirty = true;
4341
- emitChange(previousRendered, previousPoints, previousOptions, previousStyle, previousNonGeometryDirty, previousSizeAnchor, currentRendered, previousTextAmplifiers, previousAmplifierPlacements, previousProperties, "programmatic", "Change size anchor");
4363
+ emitChange(previousRendered, previousPoints, previousOptions, previousStyle, previousNonGeometryDirty, previousSizeAnchor, currentRendered, previousTextAmplifiers, previousAmplifierPlacements, previousProperties, "programmatic", nextOptions ? "Change size mode" : "Change size anchor");
4342
4364
  }
4343
4365
  function modesEqual(a, b) {
4344
4366
  if (a.length !== b.length) return false;
@@ -4473,8 +4495,8 @@ function runEdit(opts) {
4473
4495
  setAmplifierPlacements(partial) {
4474
4496
  setAmplifierPlacements(partial);
4475
4497
  },
4476
- setSizeAnchor(next) {
4477
- setSizeAnchor(next);
4498
+ setSizeAnchor(next, options) {
4499
+ setSizeAnchor(next, options);
4478
4500
  },
4479
4501
  onChange(listener) {
4480
4502
  if (ctx.settled) return () => {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orbat-mapper/tactical-draw",
3
- "version": "0.2.0-alpha.39",
3
+ "version": "0.2.0-alpha.40",
4
4
  "description": "Engine-agnostic draw/edit core for tactical control measures (MIL-STD-2525 / APP-6). The MapAdapter ABI and bring-your-own-engine entry point for the tactical-draw package family.",
5
5
  "license": "MIT",
6
6
  "author": "Orbat Mapper",
@@ -39,7 +39,7 @@
39
39
  "access": "public"
40
40
  },
41
41
  "dependencies": {
42
- "@orbat-mapper/control-measures": "^0.2.0-alpha.28"
42
+ "@orbat-mapper/control-measures": "^0.2.0-alpha.30"
43
43
  },
44
44
  "peerDependencies": {
45
45
  "vitest": ">=4.0.0"