@canvas-harness/core 0.1.6 → 0.1.7

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.cjs CHANGED
@@ -233,53 +233,6 @@ var rotatePoint = (px, py, cx, cy, cos, sin) => {
233
233
  return { x: cx + dx * cos - dy * sin, y: cy + dx * sin + dy * cos };
234
234
  };
235
235
 
236
- // src/edges/auto-route.ts
237
- var CONTROL_MAX = 200;
238
- var CONTROL_FRACTION = 0.4;
239
- var sideOf = (node, localX, localY) => {
240
- const distLeft = localX;
241
- const distRight = node.w - localX;
242
- const distTop = localY;
243
- const distBottom = node.h - localY;
244
- const minDist = Math.min(distLeft, distRight, distTop, distBottom);
245
- if (minDist === distLeft) return "w";
246
- if (minDist === distRight) return "e";
247
- if (minDist === distTop) return "n";
248
- return "s";
249
- };
250
- var sideNormalLocal = (side) => {
251
- switch (side) {
252
- case "n":
253
- return { x: 0, y: -1 };
254
- case "s":
255
- return { x: 0, y: 1 };
256
- case "e":
257
- return { x: 1, y: 0 };
258
- case "w":
259
- return { x: -1, y: 0 };
260
- }
261
- };
262
- var rotateVecByAngle = (v, angle) => {
263
- if (angle === 0) return v;
264
- const cos = Math.cos(angle);
265
- const sin = Math.sin(angle);
266
- return { x: v.x * cos - v.y * sin, y: v.x * sin + v.y * cos };
267
- };
268
- var autoRouteControls = (sourceWorld, targetWorld, sourceNormalWorld, targetNormalWorld) => {
269
- const dx = targetWorld.x - sourceWorld.x;
270
- const dy = targetWorld.y - sourceWorld.y;
271
- const dist = Math.hypot(dx, dy);
272
- const offset = Math.min(CONTROL_MAX, CONTROL_FRACTION * dist);
273
- const fallbackSource = dist > 0 ? { x: dx / dist, y: dy / dist } : { x: 1, y: 0 };
274
- const fallbackTarget = dist > 0 ? { x: -dx / dist, y: -dy / dist } : { x: -1, y: 0 };
275
- const ns = sourceNormalWorld ?? fallbackSource;
276
- const nt = targetNormalWorld ?? fallbackTarget;
277
- return {
278
- c1: { x: sourceWorld.x + ns.x * offset, y: sourceWorld.y + ns.y * offset },
279
- c2: { x: targetWorld.x + nt.x * offset, y: targetWorld.y + nt.y * offset }
280
- };
281
- };
282
-
283
236
  // src/edges/project.ts
284
237
  var projectEndToWorld = (end, getNode) => {
285
238
  if (!isAttached(end)) return end.worldPoint;
@@ -328,6 +281,112 @@ var projectToNodeBoundary = (world, node) => {
328
281
  return { x: clampedX, y: node.h };
329
282
  };
330
283
 
284
+ // src/edges/auto-route.ts
285
+ var CONTROL_MAX = 200;
286
+ var CONTROL_FRACTION = 0.4;
287
+ var BOUNDARY_EPS = 0.5;
288
+ var isLocalOffsetInsideBody = (localOffset, node) => {
289
+ const onLeft = Math.abs(localOffset.x) <= BOUNDARY_EPS;
290
+ const onRight = Math.abs(localOffset.x - node.w) <= BOUNDARY_EPS;
291
+ const onTop = Math.abs(localOffset.y) <= BOUNDARY_EPS;
292
+ const onBottom = Math.abs(localOffset.y - node.h) <= BOUNDARY_EPS;
293
+ const inside = localOffset.x > -BOUNDARY_EPS && localOffset.x < node.w + BOUNDARY_EPS && localOffset.y > -BOUNDARY_EPS && localOffset.y < node.h + BOUNDARY_EPS;
294
+ return inside && !onLeft && !onRight && !onTop && !onBottom;
295
+ };
296
+ var sideOf = (node, localX, localY) => {
297
+ const distLeft = localX;
298
+ const distRight = node.w - localX;
299
+ const distTop = localY;
300
+ const distBottom = node.h - localY;
301
+ const minDist = Math.min(distLeft, distRight, distTop, distBottom);
302
+ if (minDist === distLeft) return "w";
303
+ if (minDist === distRight) return "e";
304
+ if (minDist === distTop) return "n";
305
+ return "s";
306
+ };
307
+ var sideNormalLocal = (side) => {
308
+ switch (side) {
309
+ case "n":
310
+ return { x: 0, y: -1 };
311
+ case "s":
312
+ return { x: 0, y: 1 };
313
+ case "e":
314
+ return { x: 1, y: 0 };
315
+ case "w":
316
+ return { x: -1, y: 0 };
317
+ }
318
+ };
319
+ var rotateVecByAngle = (v, angle) => {
320
+ if (angle === 0) return v;
321
+ const cos = Math.cos(angle);
322
+ const sin = Math.sin(angle);
323
+ return { x: v.x * cos - v.y * sin, y: v.x * sin + v.y * cos };
324
+ };
325
+ var autoRouteControls = (sourceWorld, targetWorld, sourceNormalWorld, targetNormalWorld) => {
326
+ const dx = targetWorld.x - sourceWorld.x;
327
+ const dy = targetWorld.y - sourceWorld.y;
328
+ const dist = Math.hypot(dx, dy);
329
+ const offset = Math.min(CONTROL_MAX, CONTROL_FRACTION * dist);
330
+ const fallbackSource = dist > 0 ? { x: dx / dist, y: dy / dist } : { x: 1, y: 0 };
331
+ const fallbackTarget = dist > 0 ? { x: -dx / dist, y: -dy / dist } : { x: -1, y: 0 };
332
+ const ns = sourceNormalWorld ?? fallbackSource;
333
+ const nt = targetNormalWorld ?? fallbackTarget;
334
+ return {
335
+ c1: { x: sourceWorld.x + ns.x * offset, y: sourceWorld.y + ns.y * offset },
336
+ c2: { x: targetWorld.x + nt.x * offset, y: targetWorld.y + nt.y * offset }
337
+ };
338
+ };
339
+ var computeAsymmetricRoute = (sourceNode, targetNode) => {
340
+ const srcCenterWorld = {
341
+ x: sourceNode.x + sourceNode.w / 2,
342
+ y: sourceNode.y + sourceNode.h / 2
343
+ };
344
+ const srcInTgtLocal = worldToNodeLocal(srcCenterWorld, targetNode);
345
+ const tgtHalfW = targetNode.w / 2;
346
+ const tgtHalfH = targetNode.h / 2;
347
+ const dxNorm = (srcInTgtLocal.x - tgtHalfW) / Math.max(1, tgtHalfW);
348
+ const dyNorm = (srcInTgtLocal.y - tgtHalfH) / Math.max(1, tgtHalfH);
349
+ const targetSide = Math.abs(dxNorm) >= Math.abs(dyNorm) ? dxNorm > 0 ? "e" : "w" : dyNorm > 0 ? "s" : "n";
350
+ let tgtEntryLocal;
351
+ if (targetSide === "n" || targetSide === "s") {
352
+ const sideY = targetSide === "n" ? 0 : targetNode.h;
353
+ const clampX = Math.max(0, Math.min(targetNode.w, srcInTgtLocal.x));
354
+ tgtEntryLocal = { x: clampX, y: sideY };
355
+ } else {
356
+ const sideX = targetSide === "w" ? 0 : targetNode.w;
357
+ const clampY = Math.max(0, Math.min(targetNode.h, srcInTgtLocal.y));
358
+ tgtEntryLocal = { x: sideX, y: clampY };
359
+ }
360
+ const targetEntryWorld = nodeLocalToWorld(tgtEntryLocal, targetNode);
361
+ const tgtEntryInSrcLocal = worldToNodeLocal(targetEntryWorld, sourceNode);
362
+ const srcHalfW = sourceNode.w / 2;
363
+ const srcHalfH = sourceNode.h / 2;
364
+ const rayDx = tgtEntryInSrcLocal.x - srcHalfW;
365
+ const rayDy = tgtEntryInSrcLocal.y - srcHalfH;
366
+ const tx = rayDx === 0 ? Number.POSITIVE_INFINITY : (rayDx > 0 ? srcHalfW : -srcHalfW) / rayDx;
367
+ const ty = rayDy === 0 ? Number.POSITIVE_INFINITY : (rayDy > 0 ? srcHalfH : -srcHalfH) / rayDy;
368
+ const t = Math.min(tx, ty);
369
+ const srcExitLocal = {
370
+ x: srcHalfW + rayDx * t,
371
+ y: srcHalfH + rayDy * t
372
+ };
373
+ const sourceExitWorld = nodeLocalToWorld(srcExitLocal, sourceNode);
374
+ const dxWorld = targetEntryWorld.x - sourceExitWorld.x;
375
+ const dyWorld = targetEntryWorld.y - sourceExitWorld.y;
376
+ const distance2 = Math.hypot(dxWorld, dyWorld);
377
+ const offset = Math.min(CONTROL_MAX, CONTROL_FRACTION * distance2);
378
+ const c1 = distance2 > 0 ? {
379
+ x: sourceExitWorld.x + dxWorld / distance2 * offset,
380
+ y: sourceExitWorld.y + dyWorld / distance2 * offset
381
+ } : { ...sourceExitWorld };
382
+ const tgtNormalWorld = rotateVecByAngle(sideNormalLocal(targetSide), targetNode.angle);
383
+ const c2 = {
384
+ x: targetEntryWorld.x + tgtNormalWorld.x * offset,
385
+ y: targetEntryWorld.y + tgtNormalWorld.y * offset
386
+ };
387
+ return { source: sourceExitWorld, target: targetEntryWorld, c1, c2 };
388
+ };
389
+
331
390
  // src/edges/clip.ts
332
391
  var fullVisibleClipResult = (samples) => ({
333
392
  startIndex: 0,
@@ -588,8 +647,8 @@ var computeEdgeGeometry = (edge, getNode) => {
588
647
  targetNodeId
589
648
  };
590
649
  }
591
- const sourceWorld = projectEndToWorld(edge.source, getNode);
592
- const targetWorld = projectEndToWorld(edge.target, getNode);
650
+ let sourceWorld = projectEndToWorld(edge.source, getNode);
651
+ let targetWorld = projectEndToWorld(edge.target, getNode);
593
652
  if (!sourceWorld || !targetWorld) return null;
594
653
  let samples;
595
654
  if (edge.pathStyle === "bezier") {
@@ -598,6 +657,12 @@ var computeEdgeGeometry = (edge, getNode) => {
598
657
  if (edge.control && edge.control.length >= 2) {
599
658
  c1 = edge.control[0];
600
659
  c2 = edge.control[1];
660
+ } else if (sourceNode && targetNode && isAttached(edge.source) && isAttached(edge.target) && isLocalOffsetInsideBody(edge.source.localOffset, sourceNode) && isLocalOffsetInsideBody(edge.target.localOffset, targetNode)) {
661
+ const r = computeAsymmetricRoute(sourceNode, targetNode);
662
+ sourceWorld = r.source;
663
+ targetWorld = r.target;
664
+ c1 = r.c1;
665
+ c2 = r.c2;
601
666
  } else {
602
667
  const sourceNormal = sourceNode && isAttached(edge.source) ? rotateVecByAngle(
603
668
  sideNormalLocal(
@@ -1607,7 +1672,7 @@ var buildPath = (type, x, y, w, h, radius) => {
1607
1672
  };
1608
1673
 
1609
1674
  // src/text/tokens.ts
1610
- var INLINE_PATTERN = /(\$[^$\n]+?\$|\*\*[^*]+\*\*|==[^=\s](?:[^=]*?[^=\s])?==|`[^`]+`|\*[^*]+\*|__[^_]+__|~~[^~]+~~|_[^_]+_|\[[^\]]+\]\([^)]+\))/g;
1675
+ var INLINE_PATTERN = /(\$\$[^\n]+?\$\$|\*\*[^*]+\*\*|==[^=\s](?:[^=]*?[^=\s])?==|`[^`]+`|\*[^*]+\*|__[^_]+__|~~[^~]+~~|_[^_]+_|\[[^\]]+\]\([^)]+\))/g;
1611
1676
  var HR_LINE_PATTERN = /^[ \t]*---[ \t]*$/;
1612
1677
  var DOUBLE_HR_LINE_PATTERN = /^[ \t]*===[ \t]*$/;
1613
1678
  var transformSymbols = (value) => value.replace(/<=>|<->|<-|->|\[\]|\[[vx]\]/gi, (match) => {
@@ -1645,8 +1710,8 @@ var tokenizeInline = (segment) => {
1645
1710
  tokens.push({ type: "link", content: transformSymbols(match.slice(1, splitIndex)) });
1646
1711
  } else if (match.startsWith("`") && match.endsWith("`")) {
1647
1712
  tokens.push({ type: "code", content: match.slice(1, -1) });
1648
- } else if (match.startsWith("$") && match.endsWith("$")) {
1649
- tokens.push({ type: "math", content: match.slice(1, -1) });
1713
+ } else if (match.startsWith("$$") && match.endsWith("$$")) {
1714
+ tokens.push({ type: "math", content: match.slice(2, -2) });
1650
1715
  } else {
1651
1716
  tokens.push({ type: "text", content: transformSymbols(match) });
1652
1717
  }