stickyflow 0.0.0-stage → 0.2.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 +157 -0
  2. package/LICENSE +202 -0
  3. package/README.md +167 -2
  4. package/dist/chunk-34PK7HEU.cjs +842 -0
  5. package/dist/chunk-34PK7HEU.cjs.map +1 -0
  6. package/dist/chunk-6JKNT2YC.js +4685 -0
  7. package/dist/chunk-6JKNT2YC.js.map +1 -0
  8. package/dist/chunk-6LQJUAD4.js +801 -0
  9. package/dist/chunk-6LQJUAD4.js.map +1 -0
  10. package/dist/chunk-IIOJFR73.cjs +3671 -0
  11. package/dist/chunk-IIOJFR73.cjs.map +1 -0
  12. package/dist/chunk-KFJIFHXG.js +8559 -0
  13. package/dist/chunk-KFJIFHXG.js.map +1 -0
  14. package/dist/chunk-N6WVHOUQ.js +3665 -0
  15. package/dist/chunk-N6WVHOUQ.js.map +1 -0
  16. package/dist/chunk-S5BVAAEF.cjs +8568 -0
  17. package/dist/chunk-S5BVAAEF.cjs.map +1 -0
  18. package/dist/chunk-YM3XFBI4.cjs +4814 -0
  19. package/dist/chunk-YM3XFBI4.cjs.map +1 -0
  20. package/dist/index.cjs +1167 -0
  21. package/dist/index.cjs.map +1 -0
  22. package/dist/index.d.cts +335 -0
  23. package/dist/index.d.ts +335 -0
  24. package/dist/index.js +1097 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/interaction/index.cjs +7358 -0
  27. package/dist/interaction/index.cjs.map +1 -0
  28. package/dist/interaction/index.d.cts +273 -0
  29. package/dist/interaction/index.d.ts +273 -0
  30. package/dist/interaction/index.js +7333 -0
  31. package/dist/interaction/index.js.map +1 -0
  32. package/dist/render-r1GYvjNm.d.cts +970 -0
  33. package/dist/render-r1GYvjNm.d.ts +970 -0
  34. package/dist/runtimeTypes-ByiafBwg.d.ts +239 -0
  35. package/dist/runtimeTypes-DwLeD-em.d.cts +239 -0
  36. package/dist/stickyflow-diagram.global.js +1442 -0
  37. package/dist/stickyflow-diagram.global.js.map +1 -0
  38. package/dist/types-T7W2yTQF.d.cts +116 -0
  39. package/dist/types-ndGA1kbl.d.ts +116 -0
  40. package/dist/viewer/index.cjs +31 -0
  41. package/dist/viewer/index.cjs.map +1 -0
  42. package/dist/viewer/index.d.cts +44 -0
  43. package/dist/viewer/index.d.ts +44 -0
  44. package/dist/viewer/index.js +6 -0
  45. package/dist/viewer/index.js.map +1 -0
  46. package/dist/web-component/index.cjs +144 -0
  47. package/dist/web-component/index.cjs.map +1 -0
  48. package/dist/web-component/index.d.cts +31 -0
  49. package/dist/web-component/index.d.ts +31 -0
  50. package/dist/web-component/index.js +141 -0
  51. package/dist/web-component/index.js.map +1 -0
  52. package/package.json +81 -4
@@ -0,0 +1,842 @@
1
+ 'use strict';
2
+
3
+ var chunkYM3XFBI4_cjs = require('./chunk-YM3XFBI4.cjs');
4
+
5
+ // src/runtime/eventing/emitter.ts
6
+ var Emitter = class {
7
+ handlers = /* @__PURE__ */ new Map();
8
+ on(name, handler) {
9
+ const eventHandlers = this.handlers.get(name) ?? /* @__PURE__ */ new Set();
10
+ this.handlers.set(name, eventHandlers);
11
+ const storedHandler = handler;
12
+ eventHandlers.add(storedHandler);
13
+ return () => eventHandlers.delete(storedHandler);
14
+ }
15
+ emit(name, event) {
16
+ const registered = this.handlers.get(name);
17
+ if (registered === void 0) {
18
+ return;
19
+ }
20
+ for (const handler of [...registered]) {
21
+ try {
22
+ handler(event);
23
+ } catch (error) {
24
+ queueMicrotask(() => {
25
+ throw error;
26
+ });
27
+ }
28
+ }
29
+ }
30
+ clear() {
31
+ this.handlers.clear();
32
+ }
33
+ };
34
+
35
+ // src/runtime/dom/contract.ts
36
+ function isCameraGesture(e) {
37
+ return e.ctrlKey || e.metaKey;
38
+ }
39
+ function parseContractVersion(svg) {
40
+ const match = /data-sf-contract="(\d+)"/.exec(svg);
41
+ return match ? Number(match[1]) : null;
42
+ }
43
+ function isContractCompatible(version) {
44
+ return version === chunkYM3XFBI4_cjs.DOM_CONTRACT_VERSION;
45
+ }
46
+ var ROLES = /* @__PURE__ */ new Set([
47
+ "entity",
48
+ "link",
49
+ "frame",
50
+ "swimlane",
51
+ "chart",
52
+ "path",
53
+ "widget",
54
+ "isometric"
55
+ ]);
56
+ function sceneRole(domRole) {
57
+ return domRole === "entity" ? "shape" : domRole;
58
+ }
59
+ function symbolDeclaredBounds(el2) {
60
+ const raw = el2.getAttribute(chunkYM3XFBI4_cjs.SYMBOL_BOUNDS_ATTR);
61
+ if (!raw) {
62
+ return null;
63
+ }
64
+ const [x, y, width, height] = raw.split(",").map(Number);
65
+ return Number.isFinite(x) && Number.isFinite(y) && Number.isFinite(width) && Number.isFinite(height) ? { x, y, width, height } : null;
66
+ }
67
+ function pathGeometryOf(el2) {
68
+ const raw = el2.getAttribute(chunkYM3XFBI4_cjs.PATH_POINTS_ATTR);
69
+ if (!raw) {
70
+ return null;
71
+ }
72
+ let points;
73
+ try {
74
+ points = JSON.parse(raw);
75
+ } catch {
76
+ return null;
77
+ }
78
+ if (!Array.isArray(points) || !points.every((point) => Array.isArray(point) && point.length === 2)) {
79
+ return null;
80
+ }
81
+ return {
82
+ points,
83
+ tension: Number(el2.getAttribute(chunkYM3XFBI4_cjs.PATH_TENSION_ATTR)) || 0,
84
+ closed: el2.getAttribute(chunkYM3XFBI4_cjs.PATH_CLOSED_ATTR) === "true"
85
+ };
86
+ }
87
+ function isometricGeometryOf(el2) {
88
+ const raw = el2.getAttribute(chunkYM3XFBI4_cjs.ISOMETRIC_SIZE_ATTR);
89
+ if (raw === null) {
90
+ return null;
91
+ }
92
+ const [width, height, depth] = raw.split(",").map(Number);
93
+ if (!Number.isFinite(width) || !Number.isFinite(height) || !Number.isFinite(depth)) {
94
+ return null;
95
+ }
96
+ const cornerRadius = Number(el2.getAttribute(chunkYM3XFBI4_cjs.CORNER_RADIUS_ATTR)) || 0;
97
+ const [labelOffsetX, labelOffsetY] = (el2.getAttribute(chunkYM3XFBI4_cjs.ISOMETRIC_LABEL_OFFSET_ATTR) ?? "0,0").split(",").map(Number);
98
+ return {
99
+ width,
100
+ height,
101
+ depth,
102
+ cornerRadius,
103
+ bounds: symbolDeclaredBounds(el2),
104
+ labelOffsetX: Number.isFinite(labelOffsetX) ? labelOffsetX : 0,
105
+ labelOffsetY: Number.isFinite(labelOffsetY) ? labelOffsetY : 0
106
+ };
107
+ }
108
+ function resolveOwner(target) {
109
+ const el2 = target?.closest("[data-sf-id]");
110
+ if (!el2) {
111
+ return null;
112
+ }
113
+ const id = el2.getAttribute("data-sf-id");
114
+ const role = el2.getAttribute("data-sf-role");
115
+ if (!id || !role || !ROLES.has(role)) {
116
+ return null;
117
+ }
118
+ return {
119
+ role: sceneRole(role),
120
+ id,
121
+ kind: el2.getAttribute("data-sf-kind") ?? void 0,
122
+ label: el2.getAttribute("aria-label") ?? void 0
123
+ };
124
+ }
125
+
126
+ // src/runtime/dom/svgNamespace.ts
127
+ var SVG_NAMESPACE = "http://www.w3.org/2000/svg";
128
+
129
+ // src/runtime/dom/alignmentGuideOverlay.ts
130
+ var NS = SVG_NAMESPACE;
131
+ var DASH = "8 4";
132
+ function el(doc, tag) {
133
+ return doc.createElementNS(NS, tag);
134
+ }
135
+ function updateAlignmentGuides(svg, guides, color) {
136
+ svg.querySelectorAll("[data-sf-alignment-guides]").forEach((g2) => {
137
+ g2.remove();
138
+ });
139
+ if (!guides.length) {
140
+ return;
141
+ }
142
+ const doc = svg.ownerDocument;
143
+ const g = el(doc, "g");
144
+ g.setAttribute("data-sf-alignment-guides", "");
145
+ g.setAttribute("pointer-events", "none");
146
+ guides.forEach((guide) => {
147
+ const line = el(doc, "line");
148
+ if (guide.orientation === "segment") {
149
+ line.setAttribute("x1", String(guide.x1));
150
+ line.setAttribute("y1", String(guide.y1));
151
+ line.setAttribute("x2", String(guide.x2));
152
+ line.setAttribute("y2", String(guide.y2));
153
+ } else if (guide.orientation === "vertical") {
154
+ line.setAttribute("x1", String(guide.position));
155
+ line.setAttribute("x2", String(guide.position));
156
+ line.setAttribute("y1", String(guide.from));
157
+ line.setAttribute("y2", String(guide.to));
158
+ } else {
159
+ line.setAttribute("y1", String(guide.position));
160
+ line.setAttribute("y2", String(guide.position));
161
+ line.setAttribute("x1", String(guide.from));
162
+ line.setAttribute("x2", String(guide.to));
163
+ }
164
+ line.setAttribute("stroke", color);
165
+ line.setAttribute("stroke-width", "1");
166
+ line.setAttribute("stroke-dasharray", DASH);
167
+ line.setAttribute("opacity", "0.8");
168
+ line.setAttribute("vector-effect", "non-scaling-stroke");
169
+ g.appendChild(line);
170
+ });
171
+ svg.appendChild(g);
172
+ }
173
+ function clearAlignmentGuides(svg) {
174
+ svg.querySelectorAll("[data-sf-alignment-guides]").forEach((g) => {
175
+ g.remove();
176
+ });
177
+ }
178
+
179
+ // src/runtime/dom/canvasObjectRoles.ts
180
+ var DERIVED_HEIGHT_ROLES = /* @__PURE__ */ new Set([]);
181
+
182
+ // src/runtime/dom/selectionOverlay/dom.ts
183
+ function svgElement(document, tag) {
184
+ return document.createElementNS(SVG_NAMESPACE, tag);
185
+ }
186
+ function selectionOverlayGroup(document, id, primary) {
187
+ const group = svgElement(document, "g");
188
+ group.setAttribute("data-sf-selection-overlay", id);
189
+ group.setAttribute("pointer-events", "none");
190
+ const transform = primary.getAttribute("transform");
191
+ if (transform) {
192
+ group.setAttribute("transform", transform);
193
+ }
194
+ return group;
195
+ }
196
+
197
+ // src/runtime/dom/changeOverlay.ts
198
+ var OVERLAY_ATTR = "data-sf-change-overlay";
199
+ var CHANGE_COLOR = "#f59e0b";
200
+ var FLASH_DURATION_MS = 1300;
201
+ var REDUCED_MOTION_DURATION_MS = 400;
202
+ function changeOverlayGroup(document, id, primary) {
203
+ const group = svgElement(document, "g");
204
+ group.setAttribute(OVERLAY_ATTR, id);
205
+ group.setAttribute("pointer-events", "none");
206
+ const transform = primary.getAttribute("transform");
207
+ if (transform) {
208
+ group.setAttribute("transform", transform);
209
+ }
210
+ return group;
211
+ }
212
+ function startChangeFade(target, reducedMotion) {
213
+ if (reducedMotion) {
214
+ return;
215
+ }
216
+ target.animate([{ opacity: 1 }, { opacity: 0 }], {
217
+ duration: FLASH_DURATION_MS,
218
+ easing: "linear",
219
+ fill: "forwards"
220
+ });
221
+ }
222
+ function shapeChangeOverlay(document, primary, id, color = CHANGE_COLOR) {
223
+ const bounds = primary.getBBox();
224
+ const group = changeOverlayGroup(document, id, primary);
225
+ const ring = svgElement(document, "rect");
226
+ ring.setAttribute("x", String(bounds.x - 4));
227
+ ring.setAttribute("y", String(bounds.y - 4));
228
+ ring.setAttribute("width", String(bounds.width + 8));
229
+ ring.setAttribute("height", String(bounds.height + 8));
230
+ ring.setAttribute("fill", "none");
231
+ ring.setAttribute("stroke", color);
232
+ ring.setAttribute("stroke-width", "3");
233
+ group.appendChild(ring);
234
+ return group;
235
+ }
236
+ function linkChangeOverlay(document, primary, id, color = CHANGE_COLOR) {
237
+ const group = changeOverlayGroup(document, id, primary);
238
+ const halo = svgElement(document, "path");
239
+ halo.setAttribute("d", primary.getAttribute("d") ?? "");
240
+ halo.setAttribute("fill", "none");
241
+ halo.setAttribute("stroke", color);
242
+ const baseWidth = Number(primary.getAttribute("stroke-width")) || 2;
243
+ halo.setAttribute("stroke-width", String(baseWidth + 6));
244
+ halo.setAttribute("stroke-linecap", "round");
245
+ halo.setAttribute("opacity", "0.6");
246
+ group.appendChild(halo);
247
+ return group;
248
+ }
249
+
250
+ // src/runtime/dom/domQuery.ts
251
+ function findOwnerNode(svg, id, predicate) {
252
+ const nodes = svg.querySelectorAll(`[data-sf-id="${CSS.escape(id)}"]`);
253
+ for (const el2 of nodes) {
254
+ if (predicate(el2)) {
255
+ return el2;
256
+ }
257
+ }
258
+ return null;
259
+ }
260
+ function findAllOwnerNodes(svg, id) {
261
+ return Array.from(svg.querySelectorAll(`[data-sf-id="${CSS.escape(id)}"]`));
262
+ }
263
+ var isPrimary = (el2) => el2.hasAttribute("data-sf-primary");
264
+ var isTextLabel = (el2) => el2.tagName.toLowerCase() === "text" && !el2.hasAttribute("data-sf-primary");
265
+ function pointerUserPoint(svg, event) {
266
+ const ctm = svg.getScreenCTM();
267
+ if (!ctm) {
268
+ return null;
269
+ }
270
+ const point = new DOMPoint(event.clientX, event.clientY).matrixTransform(ctm.inverse());
271
+ return { x: point.x, y: point.y };
272
+ }
273
+ function screenRectOf(el2) {
274
+ const bbox = el2.getBBox();
275
+ const ctm = el2.getScreenCTM();
276
+ if (!ctm) {
277
+ return { left: 0, top: 0, width: 0, height: 0 };
278
+ }
279
+ const topLeft = new DOMPoint(bbox.x, bbox.y).matrixTransform(ctm);
280
+ const bottomRight = new DOMPoint(bbox.x + bbox.width, bbox.y + bbox.height).matrixTransform(ctm);
281
+ return { left: topLeft.x, top: topLeft.y, width: bottomRight.x - topLeft.x, height: bottomRight.y - topLeft.y };
282
+ }
283
+ function pxPerUnit(svg) {
284
+ const rect = svg.getBoundingClientRect();
285
+ const { width: viewBoxWidth, height: viewBoxHeight } = svg.viewBox.baseVal;
286
+ if (rect.width <= 0 || viewBoxWidth <= 0) {
287
+ return 1;
288
+ }
289
+ const horizontal = rect.width / viewBoxWidth;
290
+ return rect.height > 0 && viewBoxHeight > 0 ? Math.min(horizontal, rect.height / viewBoxHeight) : horizontal;
291
+ }
292
+ function findIsometricApexCandidates(svg, excludeIds) {
293
+ const results = [];
294
+ svg.querySelectorAll('[data-sf-primary][data-sf-id][data-sf-role="isometric"]').forEach((node) => {
295
+ const id = node.getAttribute("data-sf-id");
296
+ if (!id || excludeIds.has(id)) {
297
+ return;
298
+ }
299
+ const geometry = isometricGeometryOf(node);
300
+ const bounds = geometry?.bounds ?? node.getBBox();
301
+ results.push({ id, apex: { x: bounds.x + (geometry?.depth ?? 0) * chunkYM3XFBI4_cjs.AXIS_COS, y: bounds.y } });
302
+ });
303
+ return results;
304
+ }
305
+ function findSnapCandidateBounds(svg, excludeIds) {
306
+ const results = [];
307
+ svg.querySelectorAll("[data-sf-primary][data-sf-id]").forEach((node) => {
308
+ const id = node.getAttribute("data-sf-id");
309
+ const role = node.getAttribute("data-sf-role");
310
+ if (!id || role === "link" || excludeIds.has(id)) {
311
+ return;
312
+ }
313
+ const bbox = node.getBBox();
314
+ results.push({ x: bbox.x, y: bbox.y, width: bbox.width, height: bbox.height });
315
+ });
316
+ return results;
317
+ }
318
+
319
+ // src/runtime/dom/selectionOverlay/scale.ts
320
+ function screenPx(svg, px) {
321
+ return px / pxPerUnit(svg);
322
+ }
323
+
324
+ // src/runtime/dom/selectionOverlay/quickDuplicate.ts
325
+ var BUBBLE_RADIUS_PX = 8;
326
+ var BUBBLE_MARGIN_PX = 15;
327
+ var PLUS_HALF_SIZE_PX = 4;
328
+ var BUBBLE_STROKE_WIDTH_PX = 1.5;
329
+ function quickDuplicatePositions(bounds, offset) {
330
+ const centerX = bounds.x + bounds.width / 2;
331
+ const centerY = bounds.y + bounds.height / 2;
332
+ return [
333
+ [centerX, bounds.y - offset, "top"],
334
+ [bounds.x + bounds.width + offset, centerY, "right"],
335
+ [centerX, bounds.y + bounds.height + offset, "bottom"],
336
+ [bounds.x - offset, centerY, "left"]
337
+ ];
338
+ }
339
+ function plusPath(x, y, halfSize) {
340
+ return `M ${x - halfSize} ${y} L ${x + halfSize} ${y} M ${x} ${y - halfSize} L ${x} ${y + halfSize}`;
341
+ }
342
+ var BUBBLE_FILL = "#e8e8e8";
343
+ var BUBBLE_STROKE = "#ccc";
344
+ var BUBBLE_HOVER_FILL = "#9b42df";
345
+ var BUBBLE_HOVER_STROKE = "#7c2fb5";
346
+ var BUBBLE_HOVER_SCALE = 1.2;
347
+ function duplicateBubble(document, x, y, radius, strokeWidth, direction) {
348
+ const bubble = svgElement(document, "circle");
349
+ bubble.setAttribute("cx", String(x));
350
+ bubble.setAttribute("cy", String(y));
351
+ bubble.setAttribute("r", String(radius));
352
+ bubble.setAttribute("fill", BUBBLE_FILL);
353
+ bubble.setAttribute("stroke", BUBBLE_STROKE);
354
+ bubble.setAttribute("stroke-width", String(strokeWidth));
355
+ bubble.setAttribute("data-sf-quick-duplicate", direction);
356
+ bubble.style.pointerEvents = "auto";
357
+ bubble.style.cursor = "pointer";
358
+ bubble.style.transition = "r 120ms ease, fill 120ms ease, stroke 120ms ease";
359
+ bubble.addEventListener("pointerenter", () => {
360
+ bubble.setAttribute("r", String(radius * BUBBLE_HOVER_SCALE));
361
+ bubble.setAttribute("fill", BUBBLE_HOVER_FILL);
362
+ bubble.setAttribute("stroke", BUBBLE_HOVER_STROKE);
363
+ const plus = bubble.nextElementSibling;
364
+ plus?.setAttribute("stroke", "#ffffff");
365
+ });
366
+ bubble.addEventListener("pointerleave", () => {
367
+ bubble.setAttribute("r", String(radius));
368
+ bubble.setAttribute("fill", BUBBLE_FILL);
369
+ bubble.setAttribute("stroke", BUBBLE_STROKE);
370
+ const plus = bubble.nextElementSibling;
371
+ plus?.setAttribute("stroke", "#999");
372
+ });
373
+ return bubble;
374
+ }
375
+ function duplicatePlus(document, x, y, halfSize, strokeWidth) {
376
+ const plus = svgElement(document, "path");
377
+ plus.setAttribute("d", plusPath(x, y, halfSize));
378
+ plus.setAttribute("stroke", "#999");
379
+ plus.setAttribute("stroke-width", String(strokeWidth));
380
+ plus.setAttribute("stroke-linecap", "round");
381
+ return plus;
382
+ }
383
+ function quickDuplicateBubbles(document, primary, id, svg) {
384
+ const group = selectionOverlayGroup(document, id, primary);
385
+ const radius = screenPx(svg, BUBBLE_RADIUS_PX);
386
+ const offset = radius + screenPx(svg, BUBBLE_MARGIN_PX);
387
+ const halfSize = screenPx(svg, PLUS_HALF_SIZE_PX);
388
+ const strokeWidth = screenPx(svg, BUBBLE_STROKE_WIDTH_PX);
389
+ const bounds = symbolDeclaredBounds(primary) ?? primary.getBBox();
390
+ for (const [x, y, direction] of quickDuplicatePositions(bounds, offset)) {
391
+ group.append(
392
+ duplicateBubble(document, x, y, radius, strokeWidth, direction),
393
+ duplicatePlus(document, x, y, halfSize, strokeWidth)
394
+ );
395
+ }
396
+ return group;
397
+ }
398
+ function updateQuickDuplicateBubbles(group, bounds) {
399
+ const bubbles = group.querySelectorAll("circle[data-sf-quick-duplicate]");
400
+ const firstRadius = Number(bubbles[0]?.getAttribute("r")) || BUBBLE_RADIUS_PX;
401
+ const offset = firstRadius * ((BUBBLE_RADIUS_PX + BUBBLE_MARGIN_PX) / BUBBLE_RADIUS_PX);
402
+ const halfSize = firstRadius * (PLUS_HALF_SIZE_PX / BUBBLE_RADIUS_PX);
403
+ for (const [index, [x, y]] of quickDuplicatePositions(bounds, offset).entries()) {
404
+ const bubble = bubbles[index];
405
+ if (!bubble) {
406
+ continue;
407
+ }
408
+ bubble.setAttribute("cx", String(x));
409
+ bubble.setAttribute("cy", String(y));
410
+ const plus = bubble.nextElementSibling;
411
+ if (plus) {
412
+ plus.setAttribute("d", plusPath(x, y, halfSize));
413
+ }
414
+ }
415
+ }
416
+
417
+ // src/runtime/dom/selectionOverlay/isometric.ts
418
+ var RING_COLOR = "#9b42df";
419
+ var HALO_EXTRA_WIDTH_PX = 2;
420
+ var SHAFT_WIDTH_PX = 3.25;
421
+ var HIT_WIDTH_PX = 14;
422
+ var ARROW_LENGTH_PX = 34;
423
+ var ARROWHEAD_LENGTH_PX = 10.5;
424
+ var ARROWHEAD_WIDTH_PX = 8.5;
425
+ function normalizeVec(v) {
426
+ const length = Math.hypot(v.x, v.y) || 1;
427
+ return { x: v.x / length, y: v.y / length };
428
+ }
429
+ function axisCursorUrl(direction) {
430
+ const angleDeg = Math.atan2(direction.y, direction.x) * 180 / Math.PI;
431
+ const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 26 26"><g transform="rotate(${angleDeg} 13 13)" stroke-linejoin="round" stroke-linecap="round"><line x1="4" y1="13" x2="22" y2="13" stroke="white" stroke-width="4.5"/><line x1="4" y1="13" x2="22" y2="13" stroke="black" stroke-width="1.6"/><path d="M4 13 L9.5 8.5 L9.5 17.5 Z" fill="black" stroke="white" stroke-width="1.5"/><path d="M22 13 L16.5 8.5 L16.5 17.5 Z" fill="black" stroke="white" stroke-width="1.5"/></g></svg>`;
432
+ return `url("data:image/svg+xml,${encodeURIComponent(svg)}") 13 13, pointer`;
433
+ }
434
+ function centroid(points) {
435
+ const sum = points.reduce((acc, p) => ({ x: acc.x + p.x, y: acc.y + p.y }), { x: 0, y: 0 });
436
+ return { x: sum.x / points.length, y: sum.y / points.length };
437
+ }
438
+ var ISO_HALO_ATTR = "data-sf-iso-halo";
439
+ function createAxisArrow(document, axis, direction, svg) {
440
+ const group = svgElement(document, "g");
441
+ group.setAttribute("data-sf-resize-handle", `iso-${axis}`);
442
+ group.style.cursor = axisCursorUrl(direction);
443
+ const hit = svgElement(document, "line");
444
+ hit.setAttribute("stroke", "transparent");
445
+ hit.setAttribute("stroke-width", String(screenPx(svg, HIT_WIDTH_PX)));
446
+ hit.setAttribute("stroke-linecap", "round");
447
+ hit.style.pointerEvents = "stroke";
448
+ group.appendChild(hit);
449
+ const shaft = svgElement(document, "line");
450
+ shaft.setAttribute("stroke", RING_COLOR);
451
+ shaft.setAttribute("stroke-width", String(screenPx(svg, SHAFT_WIDTH_PX)));
452
+ shaft.setAttribute("stroke-linecap", "round");
453
+ shaft.style.pointerEvents = "none";
454
+ group.appendChild(shaft);
455
+ const head = svgElement(document, "polygon");
456
+ head.setAttribute("fill", RING_COLOR);
457
+ head.style.pointerEvents = "none";
458
+ group.appendChild(head);
459
+ return { group, hit, shaft, head };
460
+ }
461
+ function positionAxisArrow(elements, origin, direction, svg) {
462
+ const length = screenPx(svg, ARROW_LENGTH_PX);
463
+ const headLength = screenPx(svg, ARROWHEAD_LENGTH_PX);
464
+ const headWidth = screenPx(svg, ARROWHEAD_WIDTH_PX);
465
+ const tip = { x: origin.x + direction.x * length, y: origin.y + direction.y * length };
466
+ const shaftEnd = {
467
+ x: origin.x + direction.x * (length - headLength),
468
+ y: origin.y + direction.y * (length - headLength)
469
+ };
470
+ const normal = { x: -direction.y, y: direction.x };
471
+ const headLeft = { x: shaftEnd.x + normal.x * headWidth / 2, y: shaftEnd.y + normal.y * headWidth / 2 };
472
+ const headRight = { x: shaftEnd.x - normal.x * headWidth / 2, y: shaftEnd.y - normal.y * headWidth / 2 };
473
+ elements.hit.setAttribute("x1", String(origin.x));
474
+ elements.hit.setAttribute("y1", String(origin.y));
475
+ elements.hit.setAttribute("x2", String(tip.x));
476
+ elements.hit.setAttribute("y2", String(tip.y));
477
+ elements.shaft.setAttribute("x1", String(origin.x));
478
+ elements.shaft.setAttribute("y1", String(origin.y));
479
+ elements.shaft.setAttribute("x2", String(shaftEnd.x));
480
+ elements.shaft.setAttribute("y2", String(shaftEnd.y));
481
+ elements.head.setAttribute("points", `${tip.x},${tip.y} ${headLeft.x},${headLeft.y} ${headRight.x},${headRight.y}`);
482
+ }
483
+ function axisArrow(document, origin, direction, axis, svg) {
484
+ const elements = createAxisArrow(document, axis, direction, svg);
485
+ positionAxisArrow(elements, origin, direction, svg);
486
+ return elements.group;
487
+ }
488
+ function updateAxisArrowGroup(group, origin, direction, svg) {
489
+ const hit = group.querySelector("line:nth-child(1)");
490
+ const shaft = group.querySelector("line:nth-child(2)");
491
+ const head = group.querySelector("polygon");
492
+ if (!hit || !shaft || !head) {
493
+ return;
494
+ }
495
+ positionAxisArrow({ hit, shaft, head }, origin, direction, svg);
496
+ }
497
+ function updateHalo(halo, d) {
498
+ halo.setAttribute("d", d);
499
+ }
500
+ function axisArrowPlacements(object) {
501
+ const faces = chunkYM3XFBI4_cjs.isometricFaces(object);
502
+ const apex = faces.top[0];
503
+ const right = faces.top[1];
504
+ const left = faces.top[3];
505
+ const bottom = faces.front[2];
506
+ return {
507
+ width: { origin: centroid(faces.right), direction: normalizeVec({ x: right.x - apex.x, y: right.y - apex.y }) },
508
+ height: { origin: bottom, direction: { x: 0, y: 1 } },
509
+ depth: { origin: centroid(faces.front), direction: normalizeVec({ x: left.x - apex.x, y: left.y - apex.y }) }
510
+ };
511
+ }
512
+ var DUPLICATE_MARGIN_PX = ARROW_LENGTH_PX + BUBBLE_RADIUS_PX + 10;
513
+ function reflect(point, through) {
514
+ return { x: through.x * 2 - point.x, y: through.y * 2 - point.y };
515
+ }
516
+ function quickDuplicatePlacements(object) {
517
+ const faces = chunkYM3XFBI4_cjs.isometricFaces(object);
518
+ const placements = axisArrowPlacements(object);
519
+ const visualCenter = centroid([
520
+ faces.top[0],
521
+ faces.top[1],
522
+ faces.top[2],
523
+ faces.top[3],
524
+ faces.front[2],
525
+ faces.front[3],
526
+ faces.right[2]
527
+ ]);
528
+ return {
529
+ "iso-width-pos": placements.width,
530
+ "iso-width-neg": {
531
+ origin: reflect(placements.width.origin, visualCenter),
532
+ direction: { x: -placements.width.direction.x, y: -placements.width.direction.y }
533
+ },
534
+ "iso-depth-pos": placements.depth,
535
+ "iso-depth-neg": {
536
+ origin: reflect(placements.depth.origin, visualCenter),
537
+ direction: { x: -placements.depth.direction.x, y: -placements.depth.direction.y }
538
+ },
539
+ "iso-height-pos": placements.height,
540
+ "iso-height-neg": {
541
+ origin: reflect(placements.height.origin, visualCenter),
542
+ direction: { x: -placements.height.direction.x, y: -placements.height.direction.y }
543
+ }
544
+ };
545
+ }
546
+ var ISO_DUPLICATE_BUBBLES_ATTR = "data-sf-iso-duplicate-bubbles";
547
+ var VISIBLE_FACE_DIRECTIONS = [
548
+ "iso-height-neg",
549
+ "iso-depth-pos",
550
+ "iso-width-pos"
551
+ ];
552
+ function isometricQuickDuplicateBubbles(document, object, svg) {
553
+ const group = svgElement(document, "g");
554
+ group.setAttribute(ISO_DUPLICATE_BUBBLES_ATTR, "");
555
+ const radius = screenPx(svg, BUBBLE_RADIUS_PX);
556
+ const margin = screenPx(svg, DUPLICATE_MARGIN_PX);
557
+ const halfSize = screenPx(svg, PLUS_HALF_SIZE_PX);
558
+ const strokeWidth = screenPx(svg, BUBBLE_STROKE_WIDTH_PX);
559
+ const placements = quickDuplicatePlacements(object);
560
+ for (const direction of VISIBLE_FACE_DIRECTIONS) {
561
+ const { origin, direction: dir } = placements[direction];
562
+ const x = origin.x + dir.x * margin;
563
+ const y = origin.y + dir.y * margin;
564
+ group.append(
565
+ duplicateBubble(document, x, y, radius, strokeWidth, direction),
566
+ duplicatePlus(document, x, y, halfSize, strokeWidth)
567
+ );
568
+ }
569
+ return group;
570
+ }
571
+ function isometricSelectionOverlay(document, primary, id, svg) {
572
+ const bounds = symbolDeclaredBounds(primary) ?? primary.getBBox();
573
+ const geometry = isometricGeometryOf(primary);
574
+ const group = selectionOverlayGroup(document, id, primary);
575
+ const halo = svgElement(document, "path");
576
+ halo.setAttribute(ISO_HALO_ATTR, "");
577
+ halo.setAttribute("d", primary.getAttribute("d") ?? "");
578
+ halo.setAttribute("fill", "none");
579
+ halo.setAttribute("stroke", RING_COLOR);
580
+ const baseWidth = Number(primary.getAttribute("stroke-width")) || 2;
581
+ halo.setAttribute("stroke-width", String(baseWidth + screenPx(svg, HALO_EXTRA_WIDTH_PX)));
582
+ halo.setAttribute("opacity", "0.6");
583
+ halo.style.pointerEvents = "none";
584
+ group.appendChild(halo);
585
+ const placements = axisArrowPlacements({
586
+ x: bounds.x,
587
+ y: bounds.y,
588
+ width: geometry?.width ?? bounds.width,
589
+ height: geometry?.height ?? bounds.height,
590
+ depth: geometry?.depth ?? 0
591
+ });
592
+ group.appendChild(axisArrow(document, placements.width.origin, placements.width.direction, "width", svg));
593
+ group.appendChild(axisArrow(document, placements.height.origin, placements.height.direction, "height", svg));
594
+ group.appendChild(axisArrow(document, placements.depth.origin, placements.depth.direction, "depth", svg));
595
+ group.appendChild(
596
+ isometricQuickDuplicateBubbles(
597
+ document,
598
+ {
599
+ x: bounds.x,
600
+ y: bounds.y,
601
+ width: geometry?.width ?? bounds.width,
602
+ height: geometry?.height ?? bounds.height,
603
+ depth: geometry?.depth ?? 0
604
+ },
605
+ svg
606
+ )
607
+ );
608
+ return group;
609
+ }
610
+
611
+ // src/runtime/dom/selectionOverlay/link.ts
612
+ var RING_COLOR2 = "#9b42df";
613
+ var HALO_EXTRA_WIDTH_PX2 = 4;
614
+ var ENDPOINT_RADIUS_PX = 5;
615
+ var ENDPOINT_STROKE_WIDTH_PX = 1.5;
616
+ function linkHalo(document, primary, svg) {
617
+ const halo = svgElement(document, "path");
618
+ halo.setAttribute("d", primary.getAttribute("d") ?? "");
619
+ halo.setAttribute("fill", "none");
620
+ halo.setAttribute("stroke", RING_COLOR2);
621
+ const baseWidth = Number(primary.getAttribute("stroke-width")) || 2;
622
+ halo.setAttribute("stroke-width", String(baseWidth + screenPx(svg, HALO_EXTRA_WIDTH_PX2)));
623
+ halo.setAttribute("stroke-linecap", "round");
624
+ halo.setAttribute("opacity", "0.5");
625
+ return halo;
626
+ }
627
+ function endpointHandle(document, primary, atLength, endpoint, svg) {
628
+ const point = primary.getPointAtLength(atLength);
629
+ const handle = svgElement(document, "circle");
630
+ handle.setAttribute("cx", String(point.x));
631
+ handle.setAttribute("cy", String(point.y));
632
+ handle.setAttribute("r", String(screenPx(svg, ENDPOINT_RADIUS_PX)));
633
+ handle.setAttribute("fill", RING_COLOR2);
634
+ handle.setAttribute("stroke", "white");
635
+ handle.setAttribute("stroke-width", String(screenPx(svg, ENDPOINT_STROKE_WIDTH_PX)));
636
+ handle.setAttribute("data-sf-link-endpoint", endpoint);
637
+ handle.style.pointerEvents = "auto";
638
+ handle.style.cursor = "crosshair";
639
+ return handle;
640
+ }
641
+ var SEGMENT_LENGTH_PX = 22;
642
+ var SEGMENT_THICKNESS_PX = 8;
643
+ function readSegments(primary) {
644
+ try {
645
+ return JSON.parse(primary.getAttribute("data-sf-link-segments") ?? "[]");
646
+ } catch {
647
+ return [];
648
+ }
649
+ }
650
+ function segmentHandles(document, primary, svg) {
651
+ const handles = [];
652
+ readSegments(primary).forEach((segment, index) => {
653
+ if (!segment.movable) {
654
+ return;
655
+ }
656
+ const horizontal = Math.abs(segment.bx - segment.ax) > Math.abs(segment.by - segment.ay);
657
+ const length = screenPx(svg, SEGMENT_LENGTH_PX);
658
+ const thickness = screenPx(svg, SEGMENT_THICKNESS_PX);
659
+ const width = horizontal ? length : thickness;
660
+ const height = horizontal ? thickness : length;
661
+ const handle = svgElement(document, "rect");
662
+ handle.setAttribute("x", String((segment.ax + segment.bx) / 2 - width / 2));
663
+ handle.setAttribute("y", String((segment.ay + segment.by) / 2 - height / 2));
664
+ handle.setAttribute("width", String(width));
665
+ handle.setAttribute("height", String(height));
666
+ handle.setAttribute("rx", String(thickness / 2));
667
+ handle.setAttribute("fill", "white");
668
+ handle.setAttribute("stroke", RING_COLOR2);
669
+ handle.setAttribute("stroke-width", String(screenPx(svg, ENDPOINT_STROKE_WIDTH_PX)));
670
+ handle.setAttribute("data-sf-link-segment", String(index));
671
+ handle.setAttribute("data-sf-link-segment-axis", horizontal ? "y" : "x");
672
+ handle.style.pointerEvents = "auto";
673
+ handle.style.cursor = horizontal ? "ns-resize" : "ew-resize";
674
+ handles.push(handle);
675
+ });
676
+ return handles;
677
+ }
678
+ function linkSelectionOverlay(document, primary, id, svg) {
679
+ const group = selectionOverlayGroup(document, id, primary);
680
+ const length = primary.getTotalLength();
681
+ group.append(
682
+ linkHalo(document, primary, svg),
683
+ ...segmentHandles(document, primary, svg),
684
+ endpointHandle(document, primary, 0, "from", svg),
685
+ endpointHandle(document, primary, length, "to", svg)
686
+ );
687
+ return group;
688
+ }
689
+
690
+ // src/runtime/dom/selectionOverlay/path.ts
691
+ var RING_COLOR3 = "#9b42df";
692
+ var HALO_EXTRA_WIDTH_PX3 = 4;
693
+ var POINT_RADIUS_PX = 5;
694
+ var POINT_STROKE_WIDTH_PX = 1.5;
695
+ var PATH_HALO_ATTR = "data-sf-path-halo";
696
+ function pathHalo(document, primary, svg) {
697
+ const halo = svgElement(document, "path");
698
+ halo.setAttribute(PATH_HALO_ATTR, "");
699
+ halo.setAttribute("d", primary.getAttribute("d") ?? "");
700
+ halo.setAttribute("fill", "none");
701
+ halo.setAttribute("stroke", RING_COLOR3);
702
+ const baseWidth = Number(primary.getAttribute("stroke-width")) || 2;
703
+ halo.setAttribute("stroke-width", String(baseWidth + screenPx(svg, HALO_EXTRA_WIDTH_PX3)));
704
+ halo.setAttribute("stroke-linecap", "round");
705
+ halo.setAttribute("opacity", "0.5");
706
+ return halo;
707
+ }
708
+ function pointHandle(document, x, y, index, svg) {
709
+ const handle = svgElement(document, "circle");
710
+ handle.setAttribute("cx", String(x));
711
+ handle.setAttribute("cy", String(y));
712
+ handle.setAttribute("r", String(screenPx(svg, POINT_RADIUS_PX)));
713
+ handle.setAttribute("fill", "#ffffff");
714
+ handle.setAttribute("stroke", RING_COLOR3);
715
+ handle.setAttribute("stroke-width", String(screenPx(svg, POINT_STROKE_WIDTH_PX)));
716
+ handle.setAttribute(chunkYM3XFBI4_cjs.PATH_POINT_INDEX_ATTR, String(index));
717
+ handle.style.pointerEvents = "auto";
718
+ handle.style.cursor = "move";
719
+ return handle;
720
+ }
721
+ function pathSelectionOverlay(document, primary, id, svg) {
722
+ const group = selectionOverlayGroup(document, id, primary);
723
+ group.appendChild(pathHalo(document, primary, svg));
724
+ const geometry = pathGeometryOf(primary);
725
+ for (const [index, [x, y]] of (geometry?.points ?? []).entries()) {
726
+ group.appendChild(pointHandle(document, x, y, index, svg));
727
+ }
728
+ return group;
729
+ }
730
+
731
+ // src/runtime/dom/selectionOverlay/resizeHandles.ts
732
+ var HANDLE_SIZE_PX = 6;
733
+ var HANDLE_STROKE_WIDTH_PX = 1;
734
+ var HANDLE_STROKE = "#992dff";
735
+ var HANDLE_CURSORS = {
736
+ "top-left": "nwse-resize",
737
+ top: "ns-resize",
738
+ "top-right": "nesw-resize",
739
+ right: "ew-resize",
740
+ "bottom-right": "nwse-resize",
741
+ bottom: "ns-resize",
742
+ "bottom-left": "nesw-resize",
743
+ left: "ew-resize"
744
+ };
745
+ function resizeHandlePositions(bounds) {
746
+ const centerX = bounds.x + bounds.width / 2;
747
+ const centerY = bounds.y + bounds.height / 2;
748
+ return [
749
+ [bounds.x, bounds.y, "top-left"],
750
+ [centerX, bounds.y, "top"],
751
+ [bounds.x + bounds.width, bounds.y, "top-right"],
752
+ [bounds.x + bounds.width, centerY, "right"],
753
+ [bounds.x + bounds.width, bounds.y + bounds.height, "bottom-right"],
754
+ [centerX, bounds.y + bounds.height, "bottom"],
755
+ [bounds.x, bounds.y + bounds.height, "bottom-left"],
756
+ [bounds.x, centerY, "left"]
757
+ ];
758
+ }
759
+ var LOCKED_HEIGHT_HANDLES = /* @__PURE__ */ new Set(["top", "bottom"]);
760
+ function renderResizeHandles(document, bounds, svg, lockHeight = false) {
761
+ const size = screenPx(svg, HANDLE_SIZE_PX);
762
+ const strokeWidth = screenPx(svg, HANDLE_STROKE_WIDTH_PX);
763
+ const positions = lockHeight ? resizeHandlePositions(bounds).filter(([, , name]) => !LOCKED_HEIGHT_HANDLES.has(name)) : resizeHandlePositions(bounds);
764
+ return positions.map(([centerX, centerY, name]) => {
765
+ const handle = svgElement(document, "rect");
766
+ handle.setAttribute("x", String(centerX - size / 2));
767
+ handle.setAttribute("y", String(centerY - size / 2));
768
+ handle.setAttribute("width", String(size));
769
+ handle.setAttribute("height", String(size));
770
+ handle.setAttribute("fill", "white");
771
+ handle.setAttribute("stroke", HANDLE_STROKE);
772
+ handle.setAttribute("stroke-width", String(strokeWidth));
773
+ handle.setAttribute("data-sf-resize-handle", name);
774
+ handle.style.pointerEvents = "auto";
775
+ handle.style.cursor = lockHeight ? "ew-resize" : HANDLE_CURSORS[name];
776
+ return handle;
777
+ });
778
+ }
779
+
780
+ // src/runtime/dom/selectionOverlay/shape.ts
781
+ var RING_COLOR4 = "#9b42df";
782
+ var RING_STROKE_WIDTH_PX = 3;
783
+ var RING_OFFSET_PX = 1;
784
+ function shapeSelectionOverlay(document, primary, id, svg, lockHeight = false) {
785
+ const bounds = symbolDeclaredBounds(primary) ?? primary.getBBox();
786
+ const group = selectionOverlayGroup(document, id, primary);
787
+ const offset = screenPx(svg, RING_OFFSET_PX);
788
+ const ring = svgElement(document, "rect");
789
+ ring.setAttribute("x", String(bounds.x - offset));
790
+ ring.setAttribute("y", String(bounds.y - offset));
791
+ ring.setAttribute("width", String(bounds.width + offset * 2));
792
+ ring.setAttribute("height", String(bounds.height + offset * 2));
793
+ ring.setAttribute("fill", "none");
794
+ ring.setAttribute("stroke", RING_COLOR4);
795
+ ring.setAttribute("stroke-width", String(screenPx(svg, RING_STROKE_WIDTH_PX)));
796
+ group.appendChild(ring);
797
+ group.append(...renderResizeHandles(document, bounds, svg, lockHeight));
798
+ return group;
799
+ }
800
+
801
+ exports.CHANGE_COLOR = CHANGE_COLOR;
802
+ exports.DERIVED_HEIGHT_ROLES = DERIVED_HEIGHT_ROLES;
803
+ exports.Emitter = Emitter;
804
+ exports.FLASH_DURATION_MS = FLASH_DURATION_MS;
805
+ exports.ISO_DUPLICATE_BUBBLES_ATTR = ISO_DUPLICATE_BUBBLES_ATTR;
806
+ exports.ISO_HALO_ATTR = ISO_HALO_ATTR;
807
+ exports.PATH_HALO_ATTR = PATH_HALO_ATTR;
808
+ exports.REDUCED_MOTION_DURATION_MS = REDUCED_MOTION_DURATION_MS;
809
+ exports.SVG_NAMESPACE = SVG_NAMESPACE;
810
+ exports.axisArrowPlacements = axisArrowPlacements;
811
+ exports.clearAlignmentGuides = clearAlignmentGuides;
812
+ exports.findAllOwnerNodes = findAllOwnerNodes;
813
+ exports.findIsometricApexCandidates = findIsometricApexCandidates;
814
+ exports.findOwnerNode = findOwnerNode;
815
+ exports.findSnapCandidateBounds = findSnapCandidateBounds;
816
+ exports.isCameraGesture = isCameraGesture;
817
+ exports.isContractCompatible = isContractCompatible;
818
+ exports.isPrimary = isPrimary;
819
+ exports.isTextLabel = isTextLabel;
820
+ exports.isometricGeometryOf = isometricGeometryOf;
821
+ exports.isometricSelectionOverlay = isometricSelectionOverlay;
822
+ exports.linkChangeOverlay = linkChangeOverlay;
823
+ exports.linkSelectionOverlay = linkSelectionOverlay;
824
+ exports.parseContractVersion = parseContractVersion;
825
+ exports.pathGeometryOf = pathGeometryOf;
826
+ exports.pathSelectionOverlay = pathSelectionOverlay;
827
+ exports.pointerUserPoint = pointerUserPoint;
828
+ exports.pxPerUnit = pxPerUnit;
829
+ exports.quickDuplicateBubbles = quickDuplicateBubbles;
830
+ exports.resizeHandlePositions = resizeHandlePositions;
831
+ exports.resolveOwner = resolveOwner;
832
+ exports.screenRectOf = screenRectOf;
833
+ exports.shapeChangeOverlay = shapeChangeOverlay;
834
+ exports.shapeSelectionOverlay = shapeSelectionOverlay;
835
+ exports.startChangeFade = startChangeFade;
836
+ exports.symbolDeclaredBounds = symbolDeclaredBounds;
837
+ exports.updateAlignmentGuides = updateAlignmentGuides;
838
+ exports.updateAxisArrowGroup = updateAxisArrowGroup;
839
+ exports.updateHalo = updateHalo;
840
+ exports.updateQuickDuplicateBubbles = updateQuickDuplicateBubbles;
841
+ //# sourceMappingURL=chunk-34PK7HEU.cjs.map
842
+ //# sourceMappingURL=chunk-34PK7HEU.cjs.map