stickyflow 0.11.2 → 0.12.0

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.
Files changed (52) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/binding/index.cjs +9 -9
  3. package/dist/binding/index.d.cts +3 -3
  4. package/dist/binding/index.d.ts +3 -3
  5. package/dist/binding/index.js +3 -3
  6. package/dist/{chunk-WZA3DJJH.cjs → chunk-3OF37CZX.cjs} +15 -15
  7. package/dist/{chunk-WZA3DJJH.cjs.map → chunk-3OF37CZX.cjs.map} +1 -1
  8. package/dist/{chunk-VYQ6N5SI.cjs → chunk-3XPNGIMV.cjs} +37 -37
  9. package/dist/chunk-3XPNGIMV.cjs.map +1 -0
  10. package/dist/{chunk-G6IW2IX3.js → chunk-4SXXMOXR.js} +31 -5
  11. package/dist/chunk-4SXXMOXR.js.map +1 -0
  12. package/dist/{chunk-4KBU4CFU.cjs → chunk-EG7VZJZX.cjs} +23 -23
  13. package/dist/{chunk-4KBU4CFU.cjs.map → chunk-EG7VZJZX.cjs.map} +1 -1
  14. package/dist/{chunk-BFQWCOEC.js → chunk-FYSJMUJI.js} +3 -3
  15. package/dist/{chunk-BFQWCOEC.js.map → chunk-FYSJMUJI.js.map} +1 -1
  16. package/dist/{chunk-UD6IG2PG.js → chunk-LDRUTQF7.js} +4 -4
  17. package/dist/{chunk-UD6IG2PG.js.map → chunk-LDRUTQF7.js.map} +1 -1
  18. package/dist/{chunk-DGAVCN4D.js → chunk-Q4OIDWT6.js} +6 -6
  19. package/dist/chunk-Q4OIDWT6.js.map +1 -0
  20. package/dist/{chunk-UHKFJBY5.cjs → chunk-SKGJXCAO.cjs} +31 -5
  21. package/dist/chunk-SKGJXCAO.cjs.map +1 -0
  22. package/dist/{chunk-TQIYK5OA.js → chunk-UCOMSZPC.js} +12 -10
  23. package/dist/chunk-UCOMSZPC.js.map +1 -0
  24. package/dist/{chunk-EHH6ZDK6.cjs → chunk-ZE2KRWOM.cjs} +665 -663
  25. package/dist/chunk-ZE2KRWOM.cjs.map +1 -0
  26. package/dist/index.cjs +36 -36
  27. package/dist/index.d.cts +3 -3
  28. package/dist/index.d.ts +3 -3
  29. package/dist/index.js +5 -5
  30. package/dist/interaction/index.cjs +364 -260
  31. package/dist/interaction/index.cjs.map +1 -1
  32. package/dist/interaction/index.js +131 -27
  33. package/dist/interaction/index.js.map +1 -1
  34. package/dist/{runtime-C-C5v9po.d.cts → runtime-BJDaqo6f.d.cts} +1 -1
  35. package/dist/{runtime-lCAfU-1Q.d.ts → runtime-DaconR36.d.ts} +1 -1
  36. package/dist/{runtimeTypes-BDA_CfWh.d.ts → runtimeTypes-BE_GI1yU.d.ts} +1 -1
  37. package/dist/{runtimeTypes-B7p6b1Bi.d.cts → runtimeTypes-BE_nllY6.d.cts} +1 -1
  38. package/dist/stickyflow-diagram.global.js +39 -39
  39. package/dist/stickyflow-diagram.global.js.map +1 -1
  40. package/dist/viewer/index.cjs +9 -9
  41. package/dist/viewer/index.d.cts +1 -1
  42. package/dist/viewer/index.d.ts +1 -1
  43. package/dist/viewer/index.js +4 -4
  44. package/dist/web-component/index.cjs +6 -6
  45. package/dist/web-component/index.js +4 -4
  46. package/package.json +1 -1
  47. package/dist/chunk-DGAVCN4D.js.map +0 -1
  48. package/dist/chunk-EHH6ZDK6.cjs.map +0 -1
  49. package/dist/chunk-G6IW2IX3.js.map +0 -1
  50. package/dist/chunk-TQIYK5OA.js.map +0 -1
  51. package/dist/chunk-UHKFJBY5.cjs.map +0 -1
  52. package/dist/chunk-VYQ6N5SI.cjs.map +0 -1
@@ -1,5 +1,5 @@
1
- import { screenRectOf, Emitter, resolveOwner, isCameraGesture, pointerUserPoint, clearAlignmentGuides, updateAlignmentGuides, pxPerUnit, findOwnerNode, isPrimary, SVG_NAMESPACE, isTextLabel, findSnapCandidateBounds, symbolDeclaredBounds, updateQuickDuplicateBubbles, isometricGeometryOf, updateHalo, axisArrowPlacements, updateAxisArrowGroup, PATH_HALO_ATTR, findAllOwnerNodes, findIsometricApexCandidates, DERIVED_HEIGHT_ROLES, resizeHandlePositions, ISO_HALO_ATTR, ISO_DUPLICATE_BUBBLES_ATTR, pathGeometryOf } from '../chunk-BFQWCOEC.js';
2
- import { sflToCanvasState, isIsometricObject, rgbToHex, parseHexRgb, rgbToHsv, tokenizeSource, roundedOrthogonalPathData, seriesLabelOffsetXProp, seriesLabelOffsetYProp, radarVertexPoint, AXIS_SIN, AXIS_COS, freeformPathData, CORNER_RADIUS_ATTR, isometricFaces, roundedPolygonPath, isometricTopFaceCenter, calculateLinkRoute, pointAtPort, roundedBarPath, barShapePath, formatBarLabel, LABEL_WIDTH, LEADER_INSET, clipSegmentToRect, radarValueAtPoint, radarSeriesPath, hsvToRgb, estimateTextWidth, wrapText, personLabelArea, isometricFaceCenter, PATH_POINT_INDEX_ATTR, linePathData, barLabelSize, BAR_LABEL, pillPath, getLineMidpoint, labelGapDash, pillCornerRadius, SQUARE_CORNER_ATTR, cornersRoundedRectPath, localShapePath, relativeOffsetOnRectangleSide, edgePointToward, SYMBOL_POINTS_ATTR, SYMBOL_TENSION_ATTR } from '../chunk-G6IW2IX3.js';
1
+ import { screenRectOf, Emitter, resolveOwner, isCameraGesture, pointerUserPoint, clearAlignmentGuides, updateAlignmentGuides, pxPerUnit, findOwnerNode, isPrimary, SVG_NAMESPACE, isTextLabel, findSnapCandidateBounds, symbolDeclaredBounds, updateQuickDuplicateBubbles, isometricGeometryOf, updateHalo, axisArrowPlacements, updateAxisArrowGroup, PATH_HALO_ATTR, findAllOwnerNodes, findIsometricApexCandidates, DERIVED_HEIGHT_ROLES, resizeHandlePositions, ISO_HALO_ATTR, ISO_DUPLICATE_BUBBLES_ATTR, pathGeometryOf } from '../chunk-FYSJMUJI.js';
2
+ import { sflToCanvasState, isIsometricObject, rgbToHex, parseHexRgb, rgbToHsv, tokenizeSource, roundedOrthogonalPathData, seriesLabelOffsetXProp, seriesLabelOffsetYProp, radarVertexPoint, AXIS_SIN, AXIS_COS, freeformPathData, CORNER_RADIUS_ATTR, isometricFaces, roundedPolygonPath, isometricTopFaceCenter, calculateLinkRoute, pointAtPort, roundedBarPath, barShapePath, formatBarLabel, LABEL_WIDTH, LEADER_INSET, clipSegmentToRect, radarValueAtPoint, radarSeriesPath, hsvToRgb, estimateTextWidth, wrapText, personLabelArea, isometricFaceCenter, PATH_POINT_INDEX_ATTR, linePathData, barLabelSize, BAR_LABEL, pillPath, getLineMidpoint, labelGapDash, pillCornerRadius, SQUARE_CORNER_ATTR, cornersRoundedRectPath, localShapePath, relativeOffsetOnRectangleSide, edgePointToward, SYMBOL_POINTS_ATTR, SYMBOL_TENSION_ATTR } from '../chunk-4SXXMOXR.js';
3
3
 
4
4
  // src/runtime/interaction/chartValue/coordinates.ts
5
5
  function pointerUserY(svg, event) {
@@ -3101,7 +3101,7 @@ function snapCandidates(svg, axis, excludeIds) {
3101
3101
  return values;
3102
3102
  }
3103
3103
  function movedSegments(drag, value) {
3104
- const next = drag.segments.map((segment) => ({ ...segment }));
3104
+ const next = drag.segments.map((segment2) => ({ ...segment2 }));
3105
3105
  const target = next[drag.index];
3106
3106
  const before = next[drag.index - 1];
3107
3107
  const after = next[drag.index + 1];
@@ -3127,16 +3127,16 @@ function movedSegments(drag, value) {
3127
3127
  return next;
3128
3128
  }
3129
3129
  function pathSegments(segments) {
3130
- return segments.map((segment) => {
3131
- const start = { x: segment.ax, y: segment.ay };
3132
- const end = { x: segment.bx, y: segment.by };
3130
+ return segments.map((segment2) => {
3131
+ const start = { x: segment2.ax, y: segment2.ay };
3132
+ const end = { x: segment2.bx, y: segment2.by };
3133
3133
  return {
3134
3134
  start,
3135
3135
  end,
3136
3136
  midpoint: { x: (start.x + end.x) / 2, y: (start.y + end.y) / 2 },
3137
- originalMidpoint: { x: segment.ox, y: segment.oy },
3137
+ originalMidpoint: { x: segment2.ox, y: segment2.oy },
3138
3138
  isHorizontal: Math.abs(end.x - start.x) > Math.abs(end.y - start.y),
3139
- canMove: segment.movable
3139
+ canMove: segment2.movable
3140
3140
  };
3141
3141
  });
3142
3142
  }
@@ -3163,9 +3163,9 @@ var LinkSegmentSession = class {
3163
3163
  const owner = path && resolveOwner(path);
3164
3164
  const index = Number(handle.getAttribute("data-sf-link-segment"));
3165
3165
  const segments = path ? parseSegments(path) : [];
3166
- const segment = segments[index];
3166
+ const segment2 = segments[index];
3167
3167
  const point = pointerUserPoint(this.#svg, event);
3168
- if (!path || !owner || !segment || !point) {
3168
+ if (!path || !owner || !segment2 || !point) {
3169
3169
  return;
3170
3170
  }
3171
3171
  const axis = handle.getAttribute("data-sf-link-segment-axis") === "x" ? "x" : "y";
@@ -3176,7 +3176,7 @@ var LinkSegmentSession = class {
3176
3176
  guide.setAttribute("visibility", "hidden");
3177
3177
  overlay.appendChild(guide);
3178
3178
  handle.setPointerCapture?.(event.pointerId);
3179
- const current = axis === "y" ? segment.ay : segment.ax;
3179
+ const current = axis === "y" ? segment2.ay : segment2.ax;
3180
3180
  this.#drag = {
3181
3181
  owner,
3182
3182
  path,
@@ -3185,7 +3185,7 @@ var LinkSegmentSession = class {
3185
3185
  segments,
3186
3186
  index,
3187
3187
  axis,
3188
- base: axis === "y" ? segment.oy : segment.ox,
3188
+ base: axis === "y" ? segment2.oy : segment2.ox,
3189
3189
  start: axis === "y" ? point.y : point.x,
3190
3190
  origin: current,
3191
3191
  originalD: path.getAttribute("d") ?? "",
@@ -3273,11 +3273,11 @@ var LinkSegmentSession = class {
3273
3273
  const data = roundedOrthogonalPathData(pathSegments(next), Math.max(16, strokeWidth * 4));
3274
3274
  drag.path.setAttribute("d", data);
3275
3275
  drag.overlay.querySelector("path")?.setAttribute("d", data);
3276
- const segment = next[drag.index];
3276
+ const segment2 = next[drag.index];
3277
3277
  const width = Number(drag.handle.getAttribute("width"));
3278
3278
  const height = Number(drag.handle.getAttribute("height"));
3279
- drag.handle.setAttribute("x", String((segment.ax + segment.bx) / 2 - width / 2));
3280
- drag.handle.setAttribute("y", String((segment.ay + segment.by) / 2 - height / 2));
3279
+ drag.handle.setAttribute("x", String((segment2.ax + segment2.bx) / 2 - width / 2));
3280
+ drag.handle.setAttribute("y", String((segment2.ay + segment2.by) / 2 - height / 2));
3281
3281
  const view = this.#svg.viewBox.baseVal;
3282
3282
  if (snapped === null) {
3283
3283
  drag.guide.setAttribute("visibility", "hidden");
@@ -3442,6 +3442,66 @@ function nearestCandidates(bounds, candidates, limit = 50) {
3442
3442
  return [...candidates].sort((first, second) => centerDistance(bounds, first) - centerDistance(bounds, second)).slice(0, limit);
3443
3443
  }
3444
3444
 
3445
+ // src/runtime/interaction/snapping/gaps.ts
3446
+ function rowOf(bounds, candidates, axis) {
3447
+ const [crossStart, crossSize] = axis === "x" ? ["y", "height"] : ["x", "width"];
3448
+ const [start, size] = axis === "x" ? ["x", "width"] : ["y", "height"];
3449
+ return candidates.filter(
3450
+ (candidate) => candidate[crossStart] < bounds[crossStart] + bounds[crossSize] && bounds[crossStart] < candidate[crossStart] + candidate[crossSize]
3451
+ ).map((candidate) => ({
3452
+ start: candidate[start],
3453
+ end: candidate[start] + candidate[size],
3454
+ cross: candidate[crossStart] + candidate[crossSize] / 2
3455
+ })).sort((first, second) => first.start - second.start);
3456
+ }
3457
+ function segment(axis, from, to, cross) {
3458
+ return axis === "x" ? { orientation: "segment", x1: from, y1: cross, x2: to, y2: cross } : { orientation: "segment", x1: cross, y1: from, x2: cross, y2: to };
3459
+ }
3460
+ function axisGapSnap(bounds, candidates, axis, threshold) {
3461
+ const row = rowOf(bounds, candidates, axis);
3462
+ const start = axis === "x" ? bounds.x : bounds.y;
3463
+ const size = axis === "x" ? bounds.width : bounds.height;
3464
+ const center = start + size / 2;
3465
+ const before = row.filter((span) => (span.start + span.end) / 2 < center).at(-1);
3466
+ const after = row.find((span) => (span.start + span.end) / 2 >= center);
3467
+ const pairs = row.slice(1).map((span, index) => ({ first: row[index], second: span, gap: span.start - row[index].end }));
3468
+ let best = null;
3469
+ const consider = (target, guides) => {
3470
+ const delta = target - start;
3471
+ if (Math.abs(delta) < threshold && (!best || Math.abs(delta) < Math.abs(best.delta))) {
3472
+ best = { delta, guides };
3473
+ }
3474
+ };
3475
+ if (before && after) {
3476
+ const target = (before.end + after.start - size) / 2;
3477
+ if (target >= before.end) {
3478
+ consider(target, [
3479
+ segment(axis, before.end, target, before.cross),
3480
+ segment(axis, target + size, after.start, after.cross)
3481
+ ]);
3482
+ }
3483
+ }
3484
+ for (const { first, second, gap } of pairs) {
3485
+ if (gap <= 0) {
3486
+ continue;
3487
+ }
3488
+ const existing = segment(axis, first.end, second.start, first.cross);
3489
+ if (before) {
3490
+ consider(before.end + gap, [existing, segment(axis, before.end, before.end + gap, before.cross)]);
3491
+ }
3492
+ if (after) {
3493
+ consider(after.start - gap - size, [existing, segment(axis, after.start - gap, after.start, after.cross)]);
3494
+ }
3495
+ }
3496
+ return best;
3497
+ }
3498
+ function computeGapSnap(bounds, candidates, threshold) {
3499
+ return {
3500
+ x: axisGapSnap(bounds, candidates, "x", threshold),
3501
+ y: axisGapSnap(bounds, candidates, "y", threshold)
3502
+ };
3503
+ }
3504
+
3445
3505
  // src/runtime/interaction/snapping/isometricDiagonal.ts
3446
3506
  var AXES2 = [
3447
3507
  { x: AXIS_COS, y: AXIS_SIN },
@@ -3555,17 +3615,23 @@ function snapMove(svg, drag, rawDx, rawDy) {
3555
3615
  const leadBounds = offsetBounds(drag.canvasObjects[0].draggedBounds, rawDx, rawDy);
3556
3616
  const excludedIds = new Set(drag.canvasObjects.map((canvasObject) => canvasObject.owner.id));
3557
3617
  const candidates = nearestCandidates(leadBounds, findSnapCandidateBounds(svg, excludedIds));
3618
+ const threshold = snapDistancePx(svg) / pxPerUnit(svg);
3558
3619
  const snap = computeSnap(leadBounds, candidates, {
3559
- threshold: snapDistancePx(svg) / pxPerUnit(svg),
3620
+ threshold,
3560
3621
  activeX: MOVE_ACTIVE_POINTS,
3561
3622
  activeY: MOVE_ACTIVE_POINTS,
3562
3623
  guideOverhang: GUIDE_OVERHANG2
3563
3624
  });
3564
- return {
3565
- dx: rawDx + snap.x.delta,
3566
- dy: rawDy + snap.y.delta,
3567
- guides: [snap.x.guide, snap.y.guide].filter((guide) => guide !== null)
3625
+ const gaps = computeGapSnap(leadBounds, candidates, threshold);
3626
+ const pick = (align, gap) => {
3627
+ if (gap && (!align.guide || Math.abs(gap.delta) < Math.abs(align.delta))) {
3628
+ return gap;
3629
+ }
3630
+ return { delta: align.delta, guides: align.guide ? [align.guide] : [] };
3568
3631
  };
3632
+ const x = pick(snap.x, gaps.x);
3633
+ const y = pick(snap.y, gaps.y);
3634
+ return { dx: rawDx + x.delta, dy: rawDy + y.delta, guides: [...x.guides, ...y.guides] };
3569
3635
  }
3570
3636
 
3571
3637
  // src/runtime/interaction/move/completion.ts
@@ -6411,7 +6477,7 @@ function braceDelta(masked) {
6411
6477
  }
6412
6478
 
6413
6479
  // src/runtime/interaction/sflPatch/scan/blocks.ts
6414
- var OWNER_HEADER = /^\s*(Entity|Shape|Text|Image|Container|Chart|Path|Link|Isometric|Widget|Component|Connection|Shader)\s+([A-Za-z_][A-Za-z0-9_]*)\b/;
6480
+ var OWNER_HEADER = /^\s*(Entity|Shape|Text|Image|Container|Screen|Chart|Path|Link|Isometric|Widget|Component|Connection|Shader)\s+([A-Za-z_][A-Za-z0-9_]*)\b/;
6415
6481
  var VALID_IDENT = /^[A-Za-z_][A-Za-z0-9_]*$/;
6416
6482
  function blockEndIn(masked, startLine) {
6417
6483
  let depth = 0;
@@ -6527,8 +6593,8 @@ function parsePropertyPath(path) {
6527
6593
  return null;
6528
6594
  }
6529
6595
  const blocks = [];
6530
- for (const segment of segments.slice(0, -1)) {
6531
- const block = parseBlockSegment(segment);
6596
+ for (const segment2 of segments.slice(0, -1)) {
6597
+ const block = parseBlockSegment(segment2);
6532
6598
  if (block === null) {
6533
6599
  return null;
6534
6600
  }
@@ -6536,15 +6602,15 @@ function parsePropertyPath(path) {
6536
6602
  }
6537
6603
  return { blocks, property };
6538
6604
  }
6539
- function parseBlockSegment(segment) {
6540
- const match = segment.match(BLOCK_SEGMENT);
6605
+ function parseBlockSegment(segment2) {
6606
+ const match = segment2.match(BLOCK_SEGMENT);
6541
6607
  if (!match) {
6542
6608
  return null;
6543
6609
  }
6544
6610
  return match[2] === void 0 ? { name: match[1] } : { name: match[1], id: match[2] };
6545
6611
  }
6546
- function parsePropertySegment(segment) {
6547
- const match = segment.match(PROPERTY_SEGMENT);
6612
+ function parsePropertySegment(segment2) {
6613
+ const match = segment2.match(PROPERTY_SEGMENT);
6548
6614
  if (!match) {
6549
6615
  return null;
6550
6616
  }
@@ -6883,6 +6949,42 @@ function outermostRemovalRanges(ranges) {
6883
6949
  }
6884
6950
 
6885
6951
  // src/runtime/interaction/sflPatch/canvasObjectPatch/remove.ts
6952
+ var GROUP_HEADER = /^\s*Group\s+([A-Za-z_][A-Za-z0-9_]*)\b/;
6953
+ var CHILD_BLOCK = /^\s*[A-Z][A-Za-z]*\s+[A-Za-z_]/;
6954
+ function enclosingGroups(lines, line) {
6955
+ const masked = maskLines(lines);
6956
+ if (masked === null) {
6957
+ return [];
6958
+ }
6959
+ const open = [];
6960
+ for (let i = 0; i < line; i++) {
6961
+ const delta = braceDelta(masked[i]);
6962
+ if (delta > 0) {
6963
+ const group = masked[i].match(GROUP_HEADER);
6964
+ open.push(group ? group[1] : null);
6965
+ for (let extra = 1; extra < delta; extra++) {
6966
+ open.push(null);
6967
+ }
6968
+ } else {
6969
+ open.splice(open.length + delta, -delta);
6970
+ }
6971
+ }
6972
+ return open.filter((name) => name !== null).reverse();
6973
+ }
6974
+ function removeEmptiedGroups(lines, groups) {
6975
+ for (const name of groups) {
6976
+ const masked = maskLines(lines);
6977
+ const start = masked?.findIndex((line) => line.match(GROUP_HEADER)?.[1] === name) ?? -1;
6978
+ if (!masked || start < 0) {
6979
+ return;
6980
+ }
6981
+ const end = blockEndLine(lines, start);
6982
+ if (masked.slice(start + 1, end).some((line) => CHILD_BLOCK.test(line))) {
6983
+ return;
6984
+ }
6985
+ lines.splice(start, end - start + 1);
6986
+ }
6987
+ }
6886
6988
  function removeCanvasObject(sfl, id, options = {}) {
6887
6989
  const lines = sfl.split("\n");
6888
6990
  const canvasObjectRange = findOwnerBlock(lines, id);
@@ -6898,6 +7000,7 @@ function removeCanvasObject(sfl, id, options = {}) {
6898
7000
  }
6899
7001
  return sfl;
6900
7002
  }
7003
+ const groups = enclosingGroups(lines, canvasObjectRange.start);
6901
7004
  const ranges = [canvasObjectRange];
6902
7005
  if (options.alsoRemoveLinks ?? true) {
6903
7006
  ranges.push(...findReferencingLinkRanges(lines, id));
@@ -6906,6 +7009,7 @@ function removeCanvasObject(sfl, id, options = {}) {
6906
7009
  for (const range of removalRanges) {
6907
7010
  lines.splice(range.start, range.end - range.start + 1);
6908
7011
  }
7012
+ removeEmptiedGroups(lines, groups);
6909
7013
  return lines.join("\n");
6910
7014
  }
6911
7015