@canvas-harness/core 0.1.15 → 0.1.17

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.cts CHANGED
@@ -1519,7 +1519,15 @@ type EditTarget = {
1519
1519
  };
1520
1520
  declare const idleInteractionState: () => InteractionState;
1521
1521
  /**
1522
- * Convenience: any of panning/zooming/dragging/resizing/rotating is "moving".
1522
+ * Convenience: any pointer-driven, per-frame-invalidating gesture is
1523
+ * "moving". Drives LOD swaps in the renderer (custom-node React→canvas
1524
+ * fallback, text bitmap downscale, edge-label bitmap downscale).
1525
+ *
1526
+ * `marqueeing` belongs here even though the scene doesn't translate:
1527
+ * the marquee rect updates every pointermove → static cache invalidates
1528
+ * → full repaint per frame. Without the swap, dense scenes paint
1529
+ * full-LOD React overlays + full-res text bitmaps under the moving
1530
+ * rect and the gesture janks.
1523
1531
  */
1524
1532
  declare const isMoving: (state: InteractionState) => boolean;
1525
1533
 
@@ -2124,6 +2132,11 @@ declare const toSerialized: (scene: Scene) => SerializedScene;
2124
2132
  declare const fromSerialized: (raw: SerializedScene | unknown) => Scene;
2125
2133
  /**
2126
2134
  * Convenience: dump a store's current state to wire form.
2135
+ *
2136
+ * `getFrames()` already returns frame nodes in presentation order, so the
2137
+ * id list it yields is the same value `setFrameOrder` maintains — including
2138
+ * it here is what lets a saved scene round-trip slide order. Omitted when
2139
+ * empty to keep the wire form clean (and match `toSerialized`).
2127
2140
  */
2128
2141
  declare const storeToJSON: (store: CanvasStore) => SerializedScene;
2129
2142
 
package/dist/index.d.ts CHANGED
@@ -1519,7 +1519,15 @@ type EditTarget = {
1519
1519
  };
1520
1520
  declare const idleInteractionState: () => InteractionState;
1521
1521
  /**
1522
- * Convenience: any of panning/zooming/dragging/resizing/rotating is "moving".
1522
+ * Convenience: any pointer-driven, per-frame-invalidating gesture is
1523
+ * "moving". Drives LOD swaps in the renderer (custom-node React→canvas
1524
+ * fallback, text bitmap downscale, edge-label bitmap downscale).
1525
+ *
1526
+ * `marqueeing` belongs here even though the scene doesn't translate:
1527
+ * the marquee rect updates every pointermove → static cache invalidates
1528
+ * → full repaint per frame. Without the swap, dense scenes paint
1529
+ * full-LOD React overlays + full-res text bitmaps under the moving
1530
+ * rect and the gesture janks.
1523
1531
  */
1524
1532
  declare const isMoving: (state: InteractionState) => boolean;
1525
1533
 
@@ -2124,6 +2132,11 @@ declare const toSerialized: (scene: Scene) => SerializedScene;
2124
2132
  declare const fromSerialized: (raw: SerializedScene | unknown) => Scene;
2125
2133
  /**
2126
2134
  * Convenience: dump a store's current state to wire form.
2135
+ *
2136
+ * `getFrames()` already returns frame nodes in presentation order, so the
2137
+ * id list it yields is the same value `setFrameOrder` maintains — including
2138
+ * it here is what lets a saved scene round-trip slide order. Omitted when
2139
+ * empty to keep the wire form clean (and match `toSerialized`).
2127
2140
  */
2128
2141
  declare const storeToJSON: (store: CanvasStore) => SerializedScene;
2129
2142
 
package/dist/index.js CHANGED
@@ -2593,7 +2593,7 @@ var idleInteractionState = () => ({
2593
2593
  });
2594
2594
  var isMoving = (state) => {
2595
2595
  const m = state.mode;
2596
- return m === "panning" || m === "zooming" || m === "dragging" || m === "resizing" || m === "rotating";
2596
+ return m === "panning" || m === "zooming" || m === "dragging" || m === "resizing" || m === "rotating" || m === "marqueeing";
2597
2597
  };
2598
2598
 
2599
2599
  // src/store/inverse-op.ts
@@ -3456,14 +3456,18 @@ var fromSerialized = (raw) => {
3456
3456
  ...ser.frameOrder ? { frameOrder: ser.frameOrder } : {}
3457
3457
  };
3458
3458
  };
3459
- var storeToJSON = (store) => ({
3460
- schemaVersion: SCHEMA_VERSION,
3461
- nodes: store.getAllNodes(),
3462
- edges: store.getAllEdges(),
3463
- groups: store.getAllGroups(),
3464
- camera: store.getCamera(),
3465
- selection: store.getSelection()
3466
- });
3459
+ var storeToJSON = (store) => {
3460
+ const frameOrder = store.getFrames().map((f) => f.id);
3461
+ return {
3462
+ schemaVersion: SCHEMA_VERSION,
3463
+ nodes: store.getAllNodes(),
3464
+ edges: store.getAllEdges(),
3465
+ groups: store.getAllGroups(),
3466
+ camera: store.getCamera(),
3467
+ selection: store.getSelection(),
3468
+ ...frameOrder.length > 0 ? { frameOrder } : {}
3469
+ };
3470
+ };
3467
3471
 
3468
3472
  // src/render/canvas-setup.ts
3469
3473
  var HARD_MAX_DPR = 3;
@@ -4425,8 +4429,8 @@ var darkenedStyle = (style) => {
4425
4429
  const stroke = style.strokeColor;
4426
4430
  const next = {
4427
4431
  ...style,
4428
- ...fill ? { backgroundColor: darkenHex(fill) } : {},
4429
- ...stroke ? { strokeColor: darkenHex(stroke) } : {}
4432
+ ...fill && !isFullyTransparent(fill) ? { backgroundColor: darkenHex(fill) } : {},
4433
+ ...stroke && !isFullyTransparent(stroke) ? { strokeColor: darkenHex(stroke) } : {}
4430
4434
  };
4431
4435
  darkenedStyleCache.set(style, next);
4432
4436
  return next;
@@ -4903,7 +4907,7 @@ var createRenderer = (opts) => {
4903
4907
  const excludedEdges = midpointEdgeId !== null ? /* @__PURE__ */ new Set([...baseExcludedEdges ?? [], midpointEdgeId]) : baseExcludedEdges;
4904
4908
  paintBackground(surface.ctx, { viewport, zoom: camera.z, background });
4905
4909
  const visible = visibleNodes(camera, viewport);
4906
- const isMoving2 = interaction.mode === "panning" || interaction.mode === "zooming" || interaction.mode === "dragging" || interaction.mode === "resizing" || interaction.mode === "rotating";
4910
+ const isMoving2 = isMoving(interaction);
4907
4911
  const minOnScreen = MIN_ON_SCREEN_SIZE_PX;
4908
4912
  const nextOverlaySet = /* @__PURE__ */ new Set();
4909
4913
  let drawn = 0;
@@ -5885,14 +5889,15 @@ var serializeSelection = (store) => {
5885
5889
  const n = store.getNode(id);
5886
5890
  if (n) nodes.push(n);
5887
5891
  }
5888
- const edges = [];
5892
+ const selectedEdgeIds = /* @__PURE__ */ new Set();
5889
5893
  for (const id of selectedIds) {
5890
- const e = store.getEdge(id);
5891
- if (e && bothEndsInsideSelection(e, selectedNodeIds)) edges.push(e);
5894
+ if (store.getEdge(id)) selectedEdgeIds.add(id);
5892
5895
  }
5896
+ const edges = [];
5893
5897
  for (const e of store.getAllEdges()) {
5894
- if (edges.includes(e)) continue;
5895
- if (bothEndsInsideSelection(e, selectedNodeIds)) edges.push(e);
5898
+ if (!bothEndsInsideSelection(e, selectedNodeIds)) continue;
5899
+ if (hasFreeFloatingEnd(e) && !selectedEdgeIds.has(e.id)) continue;
5900
+ edges.push(e);
5896
5901
  }
5897
5902
  return {
5898
5903
  v: SCHEMA_VERSION,
@@ -5909,6 +5914,7 @@ var endInside = (end, ids) => {
5909
5914
  if (!isAttached(end)) return true;
5910
5915
  return ids.has(end.nodeId);
5911
5916
  };
5917
+ var hasFreeFloatingEnd = (edge) => !isAttached(edge.source) || !isAttached(edge.target);
5912
5918
  var clipBboxCenter = (nodes) => {
5913
5919
  if (nodes.length === 0) return { x: 0, y: 0 };
5914
5920
  let minX = Number.POSITIVE_INFINITY;