mce 0.18.4 → 0.18.5

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.js CHANGED
@@ -151,6 +151,33 @@ var imageExts = Object.values({
151
151
  var imageExtRe = new RegExp(`\\.(?:${imageExts.map((v) => v.substring(1)).join("|")})`, "i");
152
152
  //#endregion
153
153
  //#region src/utils/create.ts
154
+ var RECT_PATH$1 = "M0 0h24v24H0z";
155
+ var FLOW_CONNECTION_POINTS = [
156
+ {
157
+ idx: 0,
158
+ x: 1,
159
+ y: .5,
160
+ ang: 0
161
+ },
162
+ {
163
+ idx: 1,
164
+ x: 0,
165
+ y: .5,
166
+ ang: Math.PI
167
+ },
168
+ {
169
+ idx: 2,
170
+ x: .5,
171
+ y: 1,
172
+ ang: Math.PI / 2
173
+ },
174
+ {
175
+ idx: 3,
176
+ x: .5,
177
+ y: 0,
178
+ ang: -Math.PI / 2
179
+ }
180
+ ];
154
181
  function createShapeElement(shape, fill, outline) {
155
182
  return {
156
183
  shape,
@@ -191,6 +218,110 @@ async function createImageElement(image) {
191
218
  }
192
219
  };
193
220
  }
221
+ /**
222
+ * A rounded panel with a bold title and optional body, composed as child text
223
+ * elements (so each line keeps its own styling and can be edited in place).
224
+ */
225
+ function createCardElement(title, options = {}) {
226
+ const { body, width = 220, height = 130, fill = "#ffffff", outline = {
227
+ color: "#e5e7eb",
228
+ width: 1
229
+ }, borderRadius = 12, padding = 16, titleStyle, bodyStyle } = options;
230
+ const children = [{
231
+ style: {
232
+ left: padding,
233
+ top: padding,
234
+ width: width - padding * 2,
235
+ fontSize: 18,
236
+ fontWeight: 700,
237
+ color: "#111827",
238
+ ...titleStyle
239
+ },
240
+ text: { content: normalizeTextContent(title) },
241
+ meta: { inCanvasIs: "Element2D" }
242
+ }];
243
+ if (body) children.push({
244
+ style: {
245
+ left: padding,
246
+ top: padding + 32,
247
+ width: width - padding * 2,
248
+ fontSize: 14,
249
+ color: "#6b7280",
250
+ ...bodyStyle
251
+ },
252
+ text: { content: normalizeTextContent(body) },
253
+ meta: { inCanvasIs: "Element2D" }
254
+ });
255
+ return {
256
+ style: {
257
+ width,
258
+ height,
259
+ borderRadius,
260
+ overflow: "hidden"
261
+ },
262
+ shape: [{ data: RECT_PATH$1 }],
263
+ fill,
264
+ outline,
265
+ children,
266
+ meta: {
267
+ inPptIs: "Shape",
268
+ inCanvasIs: "Element2D"
269
+ }
270
+ };
271
+ }
272
+ /**
273
+ * A labelled rounded box that exposes connection points, so connectors can
274
+ * attach and route to it. Pairs with the `connection` element.
275
+ */
276
+ function createFlowNodeElement(label = "", options = {}) {
277
+ const { width = 160, height = 72, fill = "#e0edff", outline = {
278
+ color: "#4f8cff",
279
+ width: 2
280
+ }, borderRadius = 8, textStyle, connectionPoints = FLOW_CONNECTION_POINTS } = options;
281
+ return {
282
+ style: {
283
+ width,
284
+ height,
285
+ borderRadius,
286
+ textAlign: "center",
287
+ verticalAlign: "middle",
288
+ color: "#1e3a8a",
289
+ ...textStyle
290
+ },
291
+ shape: {
292
+ enabled: true,
293
+ paths: [{ data: RECT_PATH$1 }],
294
+ connectionPoints
295
+ },
296
+ fill,
297
+ outline,
298
+ text: { content: normalizeTextContent(label) },
299
+ meta: {
300
+ inPptIs: "Shape",
301
+ inCanvasIs: "Element2D"
302
+ }
303
+ };
304
+ }
305
+ /** A solid colored note with top-aligned text, e.g. for whiteboard annotations. */
306
+ function createStickyElement(content, options = {}) {
307
+ const { width = 160, height = 160, fill = "#fff3a0", color = "#3f3f46", fontSize = 16, padding = 14 } = options;
308
+ return {
309
+ style: {
310
+ width,
311
+ height,
312
+ padding,
313
+ color,
314
+ fontSize
315
+ },
316
+ shape: [{ data: RECT_PATH$1 }],
317
+ fill,
318
+ text: { content: normalizeTextContent(content) },
319
+ meta: {
320
+ inPptIs: "Shape",
321
+ inCanvasIs: "Element2D"
322
+ }
323
+ };
324
+ }
194
325
  //#endregion
195
326
  //#region src/utils/dnd.ts
196
327
  function addDragListener(downEvent, options = {}) {
@@ -906,7 +1037,7 @@ function signedArea(data, start, end, dim) {
906
1037
  return sum;
907
1038
  }
908
1039
  //#endregion
909
- //#region ../../node_modules/.pnpm/modern-path2d@1.6.0/node_modules/modern-path2d/dist/index.mjs
1040
+ //#region ../../node_modules/.pnpm/modern-path2d@1.7.0/node_modules/modern-path2d/dist/index.mjs
910
1041
  function drawPoint(ctx, x, y, options = {}) {
911
1042
  const { radius = 1 } = options;
912
1043
  ctx.moveTo(x, y);
@@ -1012,7 +1143,7 @@ var Vector2 = class Vector2 {
1012
1143
  return this.set(this._x * x, this._y * y);
1013
1144
  }
1014
1145
  divide(x = 0, y = x) {
1015
- return this.set(this._x / x, this._y / y);
1146
+ return this.set(x === 0 ? this._x : this._x / x, y === 0 ? this._y : this._y / y);
1016
1147
  }
1017
1148
  cross(p) {
1018
1149
  return this._x * p.y - this._y * p.x;
@@ -1190,9 +1321,9 @@ function getIntersectionPoint(p1, p2, q1, q2) {
1190
1321
  const s = q2.clone().sub(q1);
1191
1322
  const q1p1 = q1.clone().sub(p1);
1192
1323
  const crossRS = r.cross(s);
1193
- if (crossRS === 0) return new Vector2((p1.x + q1.x) / 2, (p1.y + q1.y) / 2);
1324
+ if (crossRS === 0) return null;
1194
1325
  const t = q1p1.cross(s) / crossRS;
1195
- if (Math.abs(t) > 1) return new Vector2((p1.x + q1.x) / 2, (p1.y + q1.y) / 2);
1326
+ if (Math.abs(t) > 1) return null;
1196
1327
  return new Vector2(p1.x + t * r.x, p1.y + t * r.y);
1197
1328
  }
1198
1329
  var FUNCTIONS_RE = /([\w-]+)\((.+?)\)/g;
@@ -1398,7 +1529,7 @@ function recursive(points, x1, y1, x2, y2, x3, y3, distanceTolerance, level) {
1398
1529
  function cross(ax, ay, bx, by, cx, cy) {
1399
1530
  return (bx - ax) * (cy - ay) - (by - ay) * (cx - ax);
1400
1531
  }
1401
- function windingNumber(px, py, polygon) {
1532
+ function windingNumber$1(px, py, polygon) {
1402
1533
  const polygonLen = polygon.length;
1403
1534
  let wn = 0;
1404
1535
  for (let i = 0, j = polygonLen - 2; i < polygonLen; j = i, i += 2) {
@@ -1417,11 +1548,18 @@ function distance(p1, p2) {
1417
1548
  const dy = p2[1] - p1[1];
1418
1549
  return Math.sqrt(dx * dx + dy * dy);
1419
1550
  }
1551
+ function aabbIntersects(a, b) {
1552
+ return a.minX <= b.maxX && a.maxX >= b.minX && a.minY <= b.maxY && a.maxY >= b.minY;
1553
+ }
1420
1554
  function nonzeroFillRule(paths) {
1421
1555
  const results = paths.map((_, i) => ({ index: i }));
1422
- const testPointsGroups = paths.map((path) => {
1556
+ const bboxes = [];
1557
+ const testPointsGroups = paths.map((path, pathIndex) => {
1423
1558
  const len = path.length;
1424
- if (!len) return [];
1559
+ if (!len) {
1560
+ bboxes[pathIndex] = null;
1561
+ return [];
1562
+ }
1425
1563
  let xMinYAuto = [Number.MAX_SAFE_INTEGER, 0];
1426
1564
  let xAutoYMin = [0, Number.MAX_SAFE_INTEGER];
1427
1565
  let xMaxYAuto = [Number.MIN_SAFE_INTEGER, 0];
@@ -1434,6 +1572,12 @@ function nonzeroFillRule(paths) {
1434
1572
  if (xMaxYAuto[0] < x) xMaxYAuto = [x, y];
1435
1573
  if (xAutoYMax[1] < y) xAutoYMax = [x, y];
1436
1574
  }
1575
+ bboxes[pathIndex] = {
1576
+ minX: xMinYAuto[0],
1577
+ minY: xAutoYMin[1],
1578
+ maxX: xMaxYAuto[0],
1579
+ maxY: xAutoYMax[1]
1580
+ };
1437
1581
  const mid = [(xMinYAuto[0] + xMaxYAuto[0]) / 2, (xAutoYMin[1] + xAutoYMax[1]) / 2];
1438
1582
  let xMidYMinDx;
1439
1583
  let xMidYMaxDx;
@@ -1479,13 +1623,16 @@ function nonzeroFillRule(paths) {
1479
1623
  for (let i = 0, len = paths.length; i < len; i++) {
1480
1624
  const _results = [];
1481
1625
  const testPoints = testPointsGroups[i];
1626
+ const boxI = bboxes[i];
1482
1627
  for (let j = 0; j < len; j++) {
1483
1628
  if (i === j) continue;
1629
+ const boxJ = bboxes[j];
1630
+ if (!boxI || !boxJ || !aabbIntersects(boxI, boxJ)) continue;
1484
1631
  const wnMap = {};
1485
1632
  const wnList = [];
1486
1633
  for (let p = 0, pLen = testPoints.length; p < pLen; p++) {
1487
1634
  const [x, y] = testPoints[p];
1488
- const winding = windingNumber(x, y, paths[j]);
1635
+ const winding = windingNumber$1(x, y, paths[j]);
1489
1636
  wnMap[winding] = (wnMap[winding] ?? 0) + 1;
1490
1637
  wnList.push(winding);
1491
1638
  }
@@ -1503,6 +1650,88 @@ function nonzeroFillRule(paths) {
1503
1650
  }
1504
1651
  return results;
1505
1652
  }
1653
+ function isLeft(ax, ay, bx, by, px, py) {
1654
+ return (bx - ax) * (py - ay) - (px - ax) * (by - ay);
1655
+ }
1656
+ function windingNumber(px, py, vertices) {
1657
+ const len = vertices.length;
1658
+ let wn = 0;
1659
+ for (let i = 0; i < len; i += 2) {
1660
+ const ax = vertices[i];
1661
+ const ay = vertices[i + 1];
1662
+ const k = (i + 2) % len;
1663
+ const bx = vertices[k];
1664
+ const by = vertices[k + 1];
1665
+ if (ay <= py) {
1666
+ if (by > py && isLeft(ax, ay, bx, by, px, py) > 0) wn++;
1667
+ } else if (by <= py && isLeft(ax, ay, bx, by, px, py) < 0) wn--;
1668
+ }
1669
+ return wn;
1670
+ }
1671
+ function crossingNumber(px, py, vertices) {
1672
+ const len = vertices.length;
1673
+ let cn = 0;
1674
+ for (let i = 0; i < len; i += 2) {
1675
+ const ax = vertices[i];
1676
+ const ay = vertices[i + 1];
1677
+ const k = (i + 2) % len;
1678
+ const bx = vertices[k];
1679
+ const by = vertices[k + 1];
1680
+ if (ay <= py && by > py || ay > py && by <= py) {
1681
+ if (px < ax + (py - ay) / (by - ay) * (bx - ax)) cn++;
1682
+ }
1683
+ }
1684
+ return cn;
1685
+ }
1686
+ function segmentDistance(px, py, ax, ay, bx, by) {
1687
+ const dx = bx - ax;
1688
+ const dy = by - ay;
1689
+ const lenSq = dx * dx + dy * dy;
1690
+ let t = lenSq === 0 ? 0 : ((px - ax) * dx + (py - ay) * dy) / lenSq;
1691
+ if (t < 0) t = 0;
1692
+ else if (t > 1) t = 1;
1693
+ const cx = ax + t * dx;
1694
+ const cy = ay + t * dy;
1695
+ return Math.hypot(px - cx, py - cy);
1696
+ }
1697
+ function pointInPolygon(point, vertices, fillRule = "nonzero") {
1698
+ if (vertices.length < 6) return false;
1699
+ if (fillRule === "evenodd") return (crossingNumber(point.x, point.y, vertices) & 1) === 1;
1700
+ return windingNumber(point.x, point.y, vertices) !== 0;
1701
+ }
1702
+ function pointInPolygons(point, polygons, fillRule = "nonzero") {
1703
+ const { x, y } = point;
1704
+ if (fillRule === "evenodd") {
1705
+ let cn = 0;
1706
+ for (let i = 0, len = polygons.length; i < len; i++) {
1707
+ const ring = polygons[i];
1708
+ if (ring.length >= 6) cn += crossingNumber(x, y, ring);
1709
+ }
1710
+ return (cn & 1) === 1;
1711
+ }
1712
+ let wn = 0;
1713
+ for (let i = 0, len = polygons.length; i < len; i++) {
1714
+ const ring = polygons[i];
1715
+ if (ring.length >= 6) wn += windingNumber(x, y, ring);
1716
+ }
1717
+ return wn !== 0;
1718
+ }
1719
+ function pointToPolylineDistance(point, vertices, closed = false) {
1720
+ const len = vertices.length;
1721
+ if (len < 2) return Infinity;
1722
+ const { x: px, y: py } = point;
1723
+ if (len === 2) return Math.hypot(px - vertices[0], py - vertices[1]);
1724
+ let min = Infinity;
1725
+ for (let i = 0; i < len - 2; i += 2) {
1726
+ const d = segmentDistance(px, py, vertices[i], vertices[i + 1], vertices[i + 2], vertices[i + 3]);
1727
+ if (d < min) min = d;
1728
+ }
1729
+ if (closed && len >= 6) {
1730
+ const d = segmentDistance(px, py, vertices[len - 2], vertices[len - 1], vertices[0], vertices[1]);
1731
+ if (d < min) min = d;
1732
+ }
1733
+ return min;
1734
+ }
1506
1735
  function quadraticBezierP0(t, p) {
1507
1736
  const k = 1 - t;
1508
1737
  return k * k * p;
@@ -2695,6 +2924,39 @@ var dataUri = "data:image/svg+xml;";
2695
2924
  var Curve = class {
2696
2925
  arcLengthDivision = 200;
2697
2926
  _lengths = [];
2927
+ _adaptiveCache;
2928
+ /**
2929
+ * Parent composite, set lazily when a composite caches its children. Lets
2930
+ * {@link invalidate} propagate up so an ancestor's caches refresh too.
2931
+ */
2932
+ _owner;
2933
+ _invalidating = false;
2934
+ /**
2935
+ * Drop cached arc lengths and the cached sampled outline used by hit testing, then
2936
+ * bubble up to {@link _owner}. Called automatically by {@link applyTransform} and the
2937
+ * `Path2D` mutators; call it manually after mutating control-point coordinates in place —
2938
+ * the caches cannot observe such mutations.
2939
+ */
2940
+ invalidate() {
2941
+ if (this._invalidating) return this;
2942
+ this._invalidating = true;
2943
+ this._invalidateSelf();
2944
+ this._owner?.invalidate();
2945
+ this._invalidating = false;
2946
+ return this;
2947
+ }
2948
+ /** Clears this curve's own caches. Composites also clear their children (see override). */
2949
+ _invalidateSelf() {
2950
+ this._lengths.length = 0;
2951
+ this._adaptiveCache = void 0;
2952
+ }
2953
+ /**
2954
+ * Sampled outline cached for repeated hit tests (read-only — do not mutate the result).
2955
+ * Invalidated by {@link invalidate}.
2956
+ */
2957
+ _getCachedAdaptiveVertices() {
2958
+ return this._adaptiveCache ??= this.getAdaptiveVertices();
2959
+ }
2698
2960
  getPointAt(u, output = new Vector2()) {
2699
2961
  return this.getPoint(this.getUToTMapping(u), output);
2700
2962
  }
@@ -2710,6 +2972,7 @@ var Curve = class {
2710
2972
  if (isFunction) transform(p);
2711
2973
  else transform.apply(p, p);
2712
2974
  });
2975
+ this.invalidate();
2713
2976
  return this;
2714
2977
  }
2715
2978
  getUnevenVertices(count = 5, output = []) {
@@ -2836,12 +3099,21 @@ var Curve = class {
2836
3099
  return mid;
2837
3100
  }
2838
3101
  getMinMax(min = Vector2.MAX, max = Vector2.MIN) {
2839
- const potins = this.getPoints();
2840
- for (let i = 0, len = potins.length; i < len; i++) {
2841
- const p = potins[i];
2842
- min.clampMin(p);
2843
- max.clampMax(p);
3102
+ const vertices = this.getAdaptiveVertices();
3103
+ let minX = min.x;
3104
+ let minY = min.y;
3105
+ let maxX = max.x;
3106
+ let maxY = max.y;
3107
+ for (let i = 0, len = vertices.length; i < len; i += 2) {
3108
+ const x = vertices[i];
3109
+ const y = vertices[i + 1];
3110
+ if (x < minX) minX = x;
3111
+ if (y < minY) minY = y;
3112
+ if (x > maxX) maxX = x;
3113
+ if (y > maxY) maxY = y;
2844
3114
  }
3115
+ min.set(minX, minY);
3116
+ max.set(maxX, maxY);
2845
3117
  return {
2846
3118
  min: min.finite(),
2847
3119
  max: max.finite()
@@ -2851,6 +3123,42 @@ var Curve = class {
2851
3123
  const { min, max } = this.getMinMax();
2852
3124
  return new BoundingBox(min.x, min.y, max.x - min.x, max.y - min.y);
2853
3125
  }
3126
+ /**
3127
+ * Test whether a point lies inside the area enclosed by this curve.
3128
+ *
3129
+ * The curve is sampled via {@link getAdaptiveVertices} into a single implicitly closed
3130
+ * ring. This is purely geometric (it ignores any `fill`/`stroke` style), mirroring
3131
+ * `CanvasRenderingContext2D.isPointInPath`.
3132
+ *
3133
+ * Composites that hold multiple sub-paths (e.g. {@link Path2D}) override this so holes
3134
+ * are honored — a single `Curve` is always one ring.
3135
+ */
3136
+ isPointInFill(point, options = {}) {
3137
+ return pointInPolygon(point, this._getCachedAdaptiveVertices(), options.fillRule);
3138
+ }
3139
+ /**
3140
+ * Test whether a point lies on this curve's stroke, i.e. within `strokeWidth / 2 + tolerance`
3141
+ * of the sampled outline. The point must be in the same coordinate space as the curve.
3142
+ *
3143
+ * Options: `strokeWidth` (path units, default `1`), `tolerance` (extra hit slack in path
3144
+ * units, default `0` — useful for thin strokes; no coordinate scaling is assumed, so convert
3145
+ * pixel tolerance to path units upstream if your path is normalized), and `closed` (whether
3146
+ * to include the closing edge from the last vertex back to the first).
3147
+ */
3148
+ isPointInStroke(point, options = {}) {
3149
+ const { strokeWidth = 1, tolerance = 0, closed = false } = options;
3150
+ return pointToPolylineDistance(point, this._getCachedAdaptiveVertices(), closed) <= strokeWidth / 2 + tolerance;
3151
+ }
3152
+ /**
3153
+ * Concise PathKit-style fill containment test: `contains(x, y)` is shorthand for
3154
+ * {@link isPointInFill} with a `{ x, y }` point.
3155
+ */
3156
+ contains(x, y, options = {}) {
3157
+ return this.isPointInFill({
3158
+ x,
3159
+ y
3160
+ }, options);
3161
+ }
2854
3162
  getFillVertices(_options) {
2855
3163
  return this.getAdaptiveVertices();
2856
3164
  }
@@ -2980,6 +3288,64 @@ var RoundCurve = class extends Curve {
2980
3288
  }
2981
3289
  return output.set(_x, _y);
2982
3290
  }
3291
+ /**
3292
+ * Point on the ellipse at an absolute angle (mirrors {@link getPoint}'s parameterization,
3293
+ * ignoring `_diff`).
3294
+ */
3295
+ _pointAtAngle(angle, output) {
3296
+ let x = this.cx + this.rx * Math.cos(angle);
3297
+ let y = this.cy + this.ry * Math.sin(angle);
3298
+ if (this.rotate !== 0) {
3299
+ const cos = Math.cos(this.rotate);
3300
+ const sin = Math.sin(this.rotate);
3301
+ const tx = x - this.cx;
3302
+ const ty = y - this.cy;
3303
+ x = tx * cos - ty * sin + this.cx;
3304
+ y = tx * sin + ty * cos + this.cy;
3305
+ }
3306
+ return output.set(x, y);
3307
+ }
3308
+ /**
3309
+ * Analytical bounds of the (elliptical) arc: the start/end points plus the per-axis
3310
+ * extrema angles that fall within the swept interval. Matches {@link getPoint}, so it is
3311
+ * exact for `ArcCurve`/`EllipseCurve`. The `_diff` offset (used only by the legacy
3312
+ * `_getAdaptiveVerticesByCircle` path) is intentionally ignored here.
3313
+ */
3314
+ getMinMax(min = Vector2.MAX, max = Vector2.MIN) {
3315
+ const { startAngle, rotate } = this;
3316
+ const delta = this._getDeltaAngle();
3317
+ const cosT = Math.cos(rotate);
3318
+ const sinT = Math.sin(rotate);
3319
+ const p = tempV2;
3320
+ let minX = min.x;
3321
+ let minY = min.y;
3322
+ let maxX = max.x;
3323
+ let maxY = max.y;
3324
+ const consider = (angle) => {
3325
+ this._pointAtAngle(angle, p);
3326
+ if (p.x < minX) minX = p.x;
3327
+ if (p.y < minY) minY = p.y;
3328
+ if (p.x > maxX) maxX = p.x;
3329
+ if (p.y > maxY) maxY = p.y;
3330
+ };
3331
+ consider(startAngle);
3332
+ consider(startAngle + delta);
3333
+ const ax = Math.atan2(-this.ry * sinT, this.rx * cosT);
3334
+ const ay = Math.atan2(this.ry * cosT, this.rx * sinT);
3335
+ const bases = [
3336
+ ax,
3337
+ ax + Math.PI,
3338
+ ay,
3339
+ ay + Math.PI
3340
+ ];
3341
+ for (let i = 0; i < 4; i++) if (angleInSweep(bases[i], startAngle, delta)) consider(bases[i]);
3342
+ min.set(minX, minY);
3343
+ max.set(maxX, maxY);
3344
+ return {
3345
+ min: min.finite(),
3346
+ max: max.finite()
3347
+ };
3348
+ }
2983
3349
  toCommands() {
2984
3350
  const { cx, cy, rx, ry, startAngle, endAngle, clockwise, rotate } = this;
2985
3351
  const startX = cx + rx * Math.cos(startAngle) * Math.cos(rotate) - ry * Math.sin(startAngle) * Math.sin(rotate);
@@ -3050,6 +3416,7 @@ var RoundCurve = class extends Curve {
3050
3416
  this.cy = tempV2.y;
3051
3417
  if (isTransformSkewed(transform)) transfEllipseGeneric(this, transform);
3052
3418
  else transfEllipseNoSkew(this, transform);
3419
+ this.invalidate();
3053
3420
  return this;
3054
3421
  }
3055
3422
  getControlPointRefs() {
@@ -3179,6 +3546,18 @@ var RoundCurve = class extends Curve {
3179
3546
  return this;
3180
3547
  }
3181
3548
  };
3549
+ function angleInSweep(a, start, delta) {
3550
+ const PI_2 = Math.PI * 2;
3551
+ const eps = 1e-9;
3552
+ if (Math.abs(delta) >= PI_2 - eps) return true;
3553
+ let off = (a - start) % PI_2;
3554
+ if (delta >= 0) {
3555
+ if (off < -1e-9) off += PI_2;
3556
+ return off >= -1e-9 && off <= delta + eps;
3557
+ }
3558
+ if (off > eps) off -= PI_2;
3559
+ return off <= eps && off >= delta - eps;
3560
+ }
3182
3561
  function transfEllipseGeneric(curve, m) {
3183
3562
  const a = curve.rx;
3184
3563
  const b = curve.ry;
@@ -3379,6 +3758,22 @@ var CompositeCurve = class CompositeCurve extends Curve {
3379
3758
  super();
3380
3759
  this.curves = curves;
3381
3760
  }
3761
+ _adaptiveCacheLen = -1;
3762
+ _invalidateSelf() {
3763
+ super._invalidateSelf();
3764
+ this._adaptiveCacheLen = -1;
3765
+ this.curves.forEach((curve) => curve.invalidate());
3766
+ }
3767
+ _getCachedAdaptiveVertices() {
3768
+ if (!this._adaptiveCache || this._adaptiveCacheLen !== this.curves.length) {
3769
+ this.curves.forEach((curve) => {
3770
+ curve._owner = this;
3771
+ });
3772
+ this._adaptiveCache = this.getAdaptiveVertices();
3773
+ this._adaptiveCacheLen = this.curves.length;
3774
+ }
3775
+ return this._adaptiveCache;
3776
+ }
3382
3777
  getFlatCurves() {
3383
3778
  return this.curves.flatMap((curve) => {
3384
3779
  if (curve instanceof CompositeCurve) return curve.getFlatCurves();
@@ -3413,6 +3808,7 @@ var CompositeCurve = class CompositeCurve extends Curve {
3413
3808
  updateLengths() {
3414
3809
  const lengths = [];
3415
3810
  for (let i = 0, sum = 0, len = this.curves.length; i < len; i++) {
3811
+ this.curves[i]._owner = this;
3416
3812
  sum += this.curves[i].getLength();
3417
3813
  lengths.push(sum);
3418
3814
  }
@@ -3466,7 +3862,10 @@ var CompositeCurve = class CompositeCurve extends Curve {
3466
3862
  }
3467
3863
  }
3468
3864
  applyTransform(transform) {
3865
+ this._invalidating = true;
3469
3866
  this.curves.forEach((curve) => curve.applyTransform(transform));
3867
+ this._invalidating = false;
3868
+ this.invalidate();
3470
3869
  return this;
3471
3870
  }
3472
3871
  getMinMax(min = Vector2.MAX, max = Vector2.MIN) {
@@ -3723,7 +4122,7 @@ var RectangleCurve = class extends PolygonCurve {
3723
4122
  return this;
3724
4123
  }
3725
4124
  };
3726
- var RoundRectangleCurve = class extends RoundCurve {
4125
+ var RoundRectangleCurve = class extends CompositeCurve {
3727
4126
  constructor(x = 0, y = 0, width = 1, height = 1, radius = 1) {
3728
4127
  super();
3729
4128
  this.x = x;
@@ -3734,25 +4133,44 @@ var RoundRectangleCurve = class extends RoundCurve {
3734
4133
  this.update();
3735
4134
  }
3736
4135
  update() {
3737
- const { x, y, width, height, radius } = this;
3738
- const halfWidth = width / 2;
3739
- const halfHeight = height / 2;
3740
- const cx = x + halfWidth;
3741
- const cy = y + halfHeight;
3742
- const rx = Math.max(0, Math.min(radius, Math.min(halfWidth, halfHeight)));
3743
- const ry = rx;
3744
- this._center = new Vector2(cx, cy);
3745
- this._radius = new Vector2(rx, ry);
3746
- this._diff = new Vector2(halfWidth - rx, halfHeight - ry);
4136
+ const { x, y, width, height } = this;
4137
+ const r = Math.max(0, Math.min(this.radius, Math.abs(width) / 2, Math.abs(height) / 2));
4138
+ const x0 = x;
4139
+ const x1 = x + r;
4140
+ const x2 = x + width - r;
4141
+ const x3 = x + width;
4142
+ const y0 = y;
4143
+ const y1 = y + r;
4144
+ const y2 = y + height - r;
4145
+ const y3 = y + height;
4146
+ if (r <= 0) this.curves = [
4147
+ LineCurve.from(x0, y0, x3, y0),
4148
+ LineCurve.from(x3, y0, x3, y3),
4149
+ LineCurve.from(x3, y3, x0, y3),
4150
+ LineCurve.from(x0, y3, x0, y0)
4151
+ ];
4152
+ else {
4153
+ const HALF_PI = Math.PI / 2;
4154
+ this.curves = [
4155
+ LineCurve.from(x1, y0, x2, y0),
4156
+ new ArcCurve(x2, y1, r, -HALF_PI, 0, true),
4157
+ LineCurve.from(x3, y1, x3, y2),
4158
+ new ArcCurve(x2, y2, r, 0, HALF_PI, true),
4159
+ LineCurve.from(x2, y3, x1, y3),
4160
+ new ArcCurve(x1, y2, r, HALF_PI, Math.PI, true),
4161
+ LineCurve.from(x0, y2, x0, y1),
4162
+ new ArcCurve(x1, y1, r, Math.PI, Math.PI * 1.5, true)
4163
+ ];
4164
+ }
4165
+ this.invalidate();
3747
4166
  return this;
3748
4167
  }
3749
4168
  drawTo(ctx) {
3750
- const { x, y, width, height, radius } = this;
3751
- ctx.roundRect(x, y, width, height, radius);
4169
+ ctx.roundRect(this.x, this.y, this.width, this.height, this.radius);
3752
4170
  return this;
3753
4171
  }
3754
4172
  copyFrom(source) {
3755
- super.copyFrom(source);
4173
+ this.arcLengthDivision = source.arcLengthDivision;
3756
4174
  this.x = source.x;
3757
4175
  this.y = source.y;
3758
4176
  this.width = source.width;
@@ -3829,6 +4247,16 @@ var CurvePath = class extends CompositeCurve {
3829
4247
  getFillVertices(options) {
3830
4248
  return this._closeVertices(super.getFillVertices(options));
3831
4249
  }
4250
+ /**
4251
+ * Same as {@link Curve.isPointInStroke}, but `closed` defaults to this sub-path's actual
4252
+ * closed-ness: explicitly `autoClose`, or geometrically closed (first vertex === last).
4253
+ */
4254
+ isPointInStroke(point, options = {}) {
4255
+ const { strokeWidth = 1, tolerance = 0 } = options;
4256
+ const vertices = this._getCachedAdaptiveVertices();
4257
+ const len = vertices.length;
4258
+ return pointToPolylineDistance(point, vertices, options.closed ?? (this.autoClose || len >= 6 && vertices[0] === vertices[len - 2] && vertices[1] === vertices[len - 1])) <= strokeWidth / 2 + tolerance;
4259
+ }
3832
4260
  _setCurrentPoint(point) {
3833
4261
  this.currentPoint = new Vector2(point.x, point.y);
3834
4262
  if (!this.startPoint) this.startPoint = this.currentPoint.clone();
@@ -3966,6 +4394,8 @@ var CurvePath = class extends CompositeCurve {
3966
4394
  };
3967
4395
  var Path2D = class Path2D extends CompositeCurve {
3968
4396
  _meta;
4397
+ _ringsCache;
4398
+ _ringsCacheLen = -1;
3969
4399
  currentCurve = new CurvePath();
3970
4400
  style;
3971
4401
  get startPoint() {
@@ -4077,6 +4507,7 @@ var Path2D = class Path2D extends CompositeCurve {
4077
4507
  this.getControlPointRefs().forEach((point) => {
4078
4508
  point.scale(sx, sy, target);
4079
4509
  });
4510
+ this.invalidate();
4080
4511
  return this;
4081
4512
  }
4082
4513
  skew(ax, ay = 0, target = {
@@ -4086,6 +4517,7 @@ var Path2D = class Path2D extends CompositeCurve {
4086
4517
  this.getControlPointRefs().forEach((point) => {
4087
4518
  point.skew(ax, ay, target);
4088
4519
  });
4520
+ this.invalidate();
4089
4521
  return this;
4090
4522
  }
4091
4523
  rotate(rad, target = {
@@ -4095,6 +4527,7 @@ var Path2D = class Path2D extends CompositeCurve {
4095
4527
  this.getControlPointRefs().forEach((point) => {
4096
4528
  point.rotate(rad, target);
4097
4529
  });
4530
+ this.invalidate();
4098
4531
  return this;
4099
4532
  }
4100
4533
  bold(b) {
@@ -4140,47 +4573,67 @@ var Path2D = class Path2D extends CompositeCurve {
4140
4573
  }
4141
4574
  });
4142
4575
  });
4576
+ this.invalidate();
4143
4577
  return this;
4144
4578
  }
4579
+ /**
4580
+ * Test whether a point lies inside the filled area of this path.
4581
+ *
4582
+ * Each sub-path ({@link CurvePath}) is sampled into its own ring and all rings are
4583
+ * evaluated together via {@link pointInPolygons}, so holes (donut / hollow shapes) are
4584
+ * honored. This is purely geometric and ignores `style.fill` — for the `fill: 'none'`
4585
+ * fallback, gate the call upstream (see {@link Path2DSet.hitTest}).
4586
+ *
4587
+ * Defaults `fillRule` to `style.fillRule`, then `'nonzero'` (matching SVG/Canvas).
4588
+ */
4589
+ _invalidateSelf() {
4590
+ super._invalidateSelf();
4591
+ this._ringsCache = void 0;
4592
+ this._ringsCacheLen = -1;
4593
+ }
4594
+ /** Per-sub-path sampled rings, cached for repeated hit tests. */
4595
+ _getRings() {
4596
+ if (!this._ringsCache || this._ringsCacheLen !== this.curves.length) {
4597
+ this._ringsCache = this.curves.map((curve) => {
4598
+ curve._owner = this;
4599
+ return curve.getAdaptiveVertices();
4600
+ });
4601
+ this._ringsCacheLen = this.curves.length;
4602
+ }
4603
+ return this._ringsCache;
4604
+ }
4605
+ isPointInFill(point, options = {}) {
4606
+ const fillRule = options.fillRule ?? this.style.fillRule ?? "nonzero";
4607
+ return pointInPolygons(point, this._getRings(), fillRule);
4608
+ }
4609
+ /**
4610
+ * Test whether a point lies on this path's stroke. A hit on any sub-path counts.
4611
+ *
4612
+ * Defaults `strokeWidth` to this path's own {@link strokeWidth} (which is `0` when
4613
+ * `style.stroke` is `'none'`). Each sub-path infers its own closed-ness unless `closed`
4614
+ * is given explicitly.
4615
+ */
4616
+ isPointInStroke(point, options = {}) {
4617
+ const strokeWidth = options.strokeWidth ?? this.strokeWidth;
4618
+ const { tolerance = 0, closed } = options;
4619
+ return this.curves.some((curve) => curve.isPointInStroke(point, {
4620
+ strokeWidth,
4621
+ tolerance,
4622
+ closed
4623
+ }));
4624
+ }
4145
4625
  getMinMax(min = Vector2.MAX, max = Vector2.MIN, withStyle = true) {
4146
- const strokeWidth = this.strokeWidth;
4147
4626
  this.curves.forEach((curve) => {
4148
4627
  curve.getMinMax(min, max);
4149
- if (withStyle) {
4150
- if (strokeWidth > 1) {
4151
- const halfStrokeWidth = strokeWidth / 2;
4152
- const isClockwise = curve.isClockwise();
4153
- const points = [];
4154
- for (let t = 0; t <= 1; t += 1 / curve.arcLengthDivision) {
4155
- const point = curve.getPoint(t);
4156
- const normal = curve.getNormal(t);
4157
- const dist1 = normal.clone().scale(isClockwise ? halfStrokeWidth : -halfStrokeWidth);
4158
- const dist2 = normal.clone().scale(isClockwise ? -halfStrokeWidth : halfStrokeWidth);
4159
- points.push(point.clone().add(dist1), point.clone().add(dist2), point.clone().add({
4160
- x: halfStrokeWidth,
4161
- y: 0
4162
- }), point.clone().add({
4163
- x: -halfStrokeWidth,
4164
- y: 0
4165
- }), point.clone().add({
4166
- x: 0,
4167
- y: halfStrokeWidth
4168
- }), point.clone().add({
4169
- x: 0,
4170
- y: -halfStrokeWidth
4171
- }), point.clone().add({
4172
- x: halfStrokeWidth,
4173
- y: halfStrokeWidth
4174
- }), point.clone().add({
4175
- x: -halfStrokeWidth,
4176
- y: -halfStrokeWidth
4177
- }));
4178
- }
4179
- min.clampMin(...points);
4180
- max.clampMax(...points);
4181
- }
4182
- }
4183
4628
  });
4629
+ if (withStyle) {
4630
+ const strokeWidth = this.strokeWidth;
4631
+ if (strokeWidth > 1 && Number.isFinite(min.x)) {
4632
+ const half = strokeWidth / 2;
4633
+ min.set(min.x - half, min.y - half);
4634
+ max.set(max.x + half, max.y + half);
4635
+ }
4636
+ }
4184
4637
  return {
4185
4638
  min: min.finite(),
4186
4639
  max: max.finite()
@@ -4936,6 +5389,7 @@ var _0_context_default = defineMixin((editor, options) => {
4936
5389
  const textSelection = ref();
4937
5390
  const hoverElement = ref();
4938
5391
  const state = ref();
5392
+ const mode = ref("canvas");
4939
5393
  function setCursor(mode) {
4940
5394
  renderEngine.value.input.setCursor(mode);
4941
5395
  }
@@ -5030,6 +5484,7 @@ var _0_context_default = defineMixin((editor, options) => {
5030
5484
  drawboardPointer,
5031
5485
  drawboardContextMenuPointer,
5032
5486
  state,
5487
+ mode,
5033
5488
  setCursor,
5034
5489
  getGlobalPointer,
5035
5490
  parseAnchor,
@@ -5193,6 +5648,9 @@ var en_default = {
5193
5648
  "selectPreviousSibling": "Select previous sibling",
5194
5649
  "selectNextSibling": "Select next sibling",
5195
5650
  "view": "View",
5651
+ "mode": "Mode",
5652
+ "mode:canvas": "Canvas mode",
5653
+ "mode:workflow": "Workflow mode",
5196
5654
  "checkerboard": "Checkerboard",
5197
5655
  "pixelGrid": "Pixel grid",
5198
5656
  "ruler": "Ruler",
@@ -5322,6 +5780,9 @@ var zh_Hans_default = {
5322
5780
  "selectPreviousSibling": "选择前一个",
5323
5781
  "selectNextSibling": "选择后一个",
5324
5782
  "view": "视图",
5783
+ "mode": "模式",
5784
+ "mode:canvas": "画布模式",
5785
+ "mode:workflow": "工作流模式",
5325
5786
  "checkerboard": "棋盘",
5326
5787
  "pixelGrid": "像素网格",
5327
5788
  "ruler": "标尺",
@@ -6194,9 +6655,9 @@ var hotkey_default = defineMixin((editor) => {
6194
6655
  getKbd
6195
6656
  });
6196
6657
  return () => {
6197
- const { exec } = editor;
6658
+ const { exec, state } = editor;
6198
6659
  useEventListener(isClient ? window : void 0, "keydown", (e) => {
6199
- if (isInputEvent(e)) return;
6660
+ if (isInputEvent(e) || state.value === "typing") return;
6200
6661
  const eKey = parseKeyboardEvent(e);
6201
6662
  hotkeysData.value.forEach((hotkeyData) => {
6202
6663
  if (hotkeyData.enabled === false) return;
@@ -6258,6 +6719,211 @@ function createHttp() {
6258
6719
  }
6259
6720
  return { request };
6260
6721
  }
6722
+ var http_default = defineMixin((editor, options) => {
6723
+ Object.assign(editor, { http: options.http ?? createHttp() });
6724
+ });
6725
+ //#endregion
6726
+ //#region src/mixins/loader.ts
6727
+ var loader_default = defineMixin((editor) => {
6728
+ const { state } = editor;
6729
+ const loaders = reactive(/* @__PURE__ */ new Map());
6730
+ const registerLoader = (value) => {
6731
+ if (Array.isArray(value)) value.forEach((v) => registerLoader(v));
6732
+ else loaders.set(value.name, value);
6733
+ };
6734
+ const unregisterLoader = (key) => {
6735
+ loaders.delete(key);
6736
+ };
6737
+ const canLoad = async (source) => {
6738
+ for (const loader of loaders.values()) if (await loader.test(source)) return true;
6739
+ return false;
6740
+ };
6741
+ const load = async (source) => {
6742
+ state.value = "loading";
6743
+ const items = [];
6744
+ let hasLoader = false;
6745
+ try {
6746
+ for (const loader of loaders.values()) if (await loader.test(source)) {
6747
+ const res = await loader.load(source);
6748
+ if (Array.isArray(res)) items.push(...res);
6749
+ else items.push(res);
6750
+ hasLoader = true;
6751
+ break;
6752
+ }
6753
+ } finally {
6754
+ state.value = void 0;
6755
+ }
6756
+ if (!hasLoader) throw new Error(`Failed to load source "${source}"`);
6757
+ return items;
6758
+ };
6759
+ const openFileDialog = (options = {}) => {
6760
+ const { multiple = false } = options;
6761
+ return new Promise((resolve) => {
6762
+ const accepts = [];
6763
+ for (const loader of loaders.values()) if (loader.accept) accepts.push(loader.accept);
6764
+ const { onChange, open } = useFileDialog({
6765
+ accept: accepts.join(","),
6766
+ reset: true,
6767
+ multiple
6768
+ });
6769
+ onChange((files) => resolve(files ? Array.from(files) : []));
6770
+ open();
6771
+ });
6772
+ };
6773
+ Object.assign(editor, {
6774
+ loaders,
6775
+ registerLoader,
6776
+ unregisterLoader,
6777
+ canLoad,
6778
+ load,
6779
+ openFileDialog
6780
+ });
6781
+ });
6782
+ //#endregion
6783
+ //#region src/mixins/snapper.ts
6784
+ var snapper_default = defineMixin((editor) => {
6785
+ const { camera } = editor;
6786
+ const snappers = reactive(/* @__PURE__ */ new Map());
6787
+ const snapThreshold = computed(() => Math.max(1, 5 / camera.value.zoom.x));
6788
+ const registerSnapper = (key, snapper) => {
6789
+ snappers.set(key, snapper);
6790
+ };
6791
+ const unregisterSnapper = (key) => {
6792
+ snappers.delete(key);
6793
+ };
6794
+ const snap = (box) => {
6795
+ const axisX = /* @__PURE__ */ new Set();
6796
+ const axisY = /* @__PURE__ */ new Set();
6797
+ snappers.forEach((snapper) => {
6798
+ const { xLines, yLines } = snapper.getLines();
6799
+ xLines?.forEach((v) => axisX.add(v));
6800
+ yLines?.forEach((v) => axisY.add(v));
6801
+ });
6802
+ const posList = [
6803
+ [0, "x"],
6804
+ [box.width / 2, "x"],
6805
+ [box.width, "x"],
6806
+ [0, "y"],
6807
+ [box.height / 2, "y"],
6808
+ [box.height, "y"]
6809
+ ];
6810
+ for (let i = 0; i < posList.length; i++) {
6811
+ const [offset, axis] = posList[i];
6812
+ let position;
6813
+ let numArray;
6814
+ if (axis === "x") {
6815
+ position = box.left + offset;
6816
+ numArray = axisX;
6817
+ } else {
6818
+ position = box.top + offset;
6819
+ numArray = axisY;
6820
+ }
6821
+ let closest;
6822
+ let minDist = Infinity;
6823
+ for (const num of numArray) {
6824
+ const dist = num - position;
6825
+ const absDist = Math.abs(dist);
6826
+ if (absDist < minDist) {
6827
+ minDist = absDist;
6828
+ closest = num;
6829
+ }
6830
+ }
6831
+ if (minDist < snapThreshold.value) position = closest ?? position;
6832
+ if (axis === "x") box.left = position - offset;
6833
+ else box.top = position - offset;
6834
+ }
6835
+ };
6836
+ Object.assign(editor, {
6837
+ snappers,
6838
+ registerSnapper,
6839
+ unregisterSnapper,
6840
+ snap
6841
+ });
6842
+ });
6843
+ //#endregion
6844
+ //#region src/mixins/snapshot.ts
6845
+ var snapshot_default = defineMixin((editor) => {
6846
+ const { isElement, frames, frameThumbs, log, fonts, runExclusiveRender } = editor;
6847
+ async function snapshot() {
6848
+ frameThumbs.value = frames.value.map(() => ({
6849
+ instanceId: -1,
6850
+ width: 0,
6851
+ height: 0,
6852
+ url: ""
6853
+ }));
6854
+ for (let i = 0; i < frames.value.length; i++) await captureFrameScreenshot(i);
6855
+ }
6856
+ async function captureElementScreenshot(element) {
6857
+ await editor.waitUntilFontLoad();
6858
+ let data;
6859
+ if (isElement(element)) data = element.toJSON();
6860
+ else data = { ...element };
6861
+ data.style ??= {};
6862
+ data.style.top = 0;
6863
+ data.style.left = 0;
6864
+ return await runExclusiveRender(() => render({
6865
+ width: data.style.width,
6866
+ height: data.style.height,
6867
+ fonts,
6868
+ data
6869
+ }));
6870
+ }
6871
+ async function captureFrameScreenshot(index) {
6872
+ const frame = frames.value[index];
6873
+ if (frame) {
6874
+ const canvas = await captureElementScreenshot(frame);
6875
+ frameThumbs.value[index] = {
6876
+ instanceId: frame.instanceId,
6877
+ width: canvas.width,
6878
+ height: canvas.height,
6879
+ url: canvas.toDataURL()
6880
+ };
6881
+ log("captureFrameScreenshot", index);
6882
+ }
6883
+ }
6884
+ Object.assign(editor, {
6885
+ snapshot,
6886
+ captureElementScreenshot,
6887
+ captureFrameScreenshot
6888
+ });
6889
+ });
6890
+ //#endregion
6891
+ //#region src/composables/strategy.ts
6892
+ var makeMceStrategyProps = propsFactory({
6893
+ resizeStrategy: Function,
6894
+ activeStrategy: Function,
6895
+ doubleclickStrategy: Function,
6896
+ hoverStrategy: Function
6897
+ }, "makeMceStrategyProps");
6898
+ var defaultActiveStrategy = (context) => {
6899
+ const { element, editor } = context;
6900
+ if (!element) return;
6901
+ const { isRootNode, inEditorIs, isElement, elementSelection } = editor;
6902
+ const activeElement = elementSelection.value[0];
6903
+ const cb = (node) => {
6904
+ const parent = node.parent;
6905
+ if (isElement(node) && (node.equal(activeElement) || parent?.equal(activeElement) || parent?.equal(activeElement?.parent) || parent && inEditorIs(parent, "Frame") && parent.parent && isRootNode(parent.parent) || parent && isRootNode(parent))) return true;
6906
+ return false;
6907
+ };
6908
+ if (cb(element)) return element;
6909
+ return element.findAncestor(cb);
6910
+ };
6911
+ var defaultDoubleclickStrategy = (context) => {
6912
+ context.editor.exec("enter");
6913
+ };
6914
+ var defaultHoverStrategy = (context) => {
6915
+ const { element, editor } = context;
6916
+ if (!element) return;
6917
+ const { isRootNode, inEditorIs, isElement, elementSelection } = editor;
6918
+ const activeElement = elementSelection.value[0];
6919
+ const cb = (node) => {
6920
+ const parent = node.parent;
6921
+ if (isElement(node) && (node.equal(activeElement) || parent?.equal(activeElement) || parent?.equal(activeElement?.parent) || parent && inEditorIs(parent, "Frame") && parent.parent && isRootNode(parent.parent) || parent && isRootNode(parent))) return true;
6922
+ return false;
6923
+ };
6924
+ if (cb(element)) return element;
6925
+ return element.findAncestor(cb);
6926
+ };
6261
6927
  //#endregion
6262
6928
  //#region src/mixins/index.ts
6263
6929
  var mixins = [
@@ -6277,167 +6943,17 @@ var mixins = [
6277
6943
  _4_3_element_default,
6278
6944
  exporter_default,
6279
6945
  hotkey_default,
6280
- defineMixin((editor, options) => {
6281
- Object.assign(editor, { http: options.http ?? createHttp() });
6282
- }),
6283
- defineMixin((editor) => {
6284
- const { state } = editor;
6285
- const loaders = reactive(/* @__PURE__ */ new Map());
6286
- const registerLoader = (value) => {
6287
- if (Array.isArray(value)) value.forEach((v) => registerLoader(v));
6288
- else loaders.set(value.name, value);
6289
- };
6290
- const unregisterLoader = (key) => {
6291
- loaders.delete(key);
6292
- };
6293
- const canLoad = async (source) => {
6294
- for (const loader of loaders.values()) if (await loader.test(source)) return true;
6295
- return false;
6296
- };
6297
- const load = async (source) => {
6298
- state.value = "loading";
6299
- const items = [];
6300
- let hasLoader = false;
6301
- try {
6302
- for (const loader of loaders.values()) if (await loader.test(source)) {
6303
- const res = await loader.load(source);
6304
- if (Array.isArray(res)) items.push(...res);
6305
- else items.push(res);
6306
- hasLoader = true;
6307
- break;
6308
- }
6309
- } finally {
6310
- state.value = void 0;
6311
- }
6312
- if (!hasLoader) throw new Error(`Failed to load source "${source}"`);
6313
- return items;
6314
- };
6315
- const openFileDialog = (options = {}) => {
6316
- const { multiple = false } = options;
6317
- return new Promise((resolve) => {
6318
- const accepts = [];
6319
- for (const loader of loaders.values()) if (loader.accept) accepts.push(loader.accept);
6320
- const { onChange, open } = useFileDialog({
6321
- accept: accepts.join(","),
6322
- reset: true,
6323
- multiple
6324
- });
6325
- onChange((files) => resolve(files ? Array.from(files) : []));
6326
- open();
6327
- });
6328
- };
6329
- Object.assign(editor, {
6330
- loaders,
6331
- registerLoader,
6332
- unregisterLoader,
6333
- canLoad,
6334
- load,
6335
- openFileDialog
6336
- });
6337
- }),
6338
- defineMixin((editor) => {
6339
- const { camera } = editor;
6340
- const snappers = reactive(/* @__PURE__ */ new Map());
6341
- const snapThreshold = computed(() => Math.max(1, 5 / camera.value.zoom.x));
6342
- const registerSnapper = (key, snapper) => {
6343
- snappers.set(key, snapper);
6344
- };
6345
- const unregisterSnapper = (key) => {
6346
- snappers.delete(key);
6347
- };
6348
- const snap = (box) => {
6349
- const axisX = /* @__PURE__ */ new Set();
6350
- const axisY = /* @__PURE__ */ new Set();
6351
- snappers.forEach((snapper) => {
6352
- const { xLines, yLines } = snapper.getLines();
6353
- xLines?.forEach((v) => axisX.add(v));
6354
- yLines?.forEach((v) => axisY.add(v));
6355
- });
6356
- const posList = [
6357
- [0, "x"],
6358
- [box.width / 2, "x"],
6359
- [box.width, "x"],
6360
- [0, "y"],
6361
- [box.height / 2, "y"],
6362
- [box.height, "y"]
6363
- ];
6364
- for (let i = 0; i < posList.length; i++) {
6365
- const [offset, axis] = posList[i];
6366
- let position;
6367
- let numArray;
6368
- if (axis === "x") {
6369
- position = box.left + offset;
6370
- numArray = axisX;
6371
- } else {
6372
- position = box.top + offset;
6373
- numArray = axisY;
6374
- }
6375
- let closest;
6376
- let minDist = Infinity;
6377
- for (const num of numArray) {
6378
- const dist = num - position;
6379
- const absDist = Math.abs(dist);
6380
- if (absDist < minDist) {
6381
- minDist = absDist;
6382
- closest = num;
6383
- }
6384
- }
6385
- if (minDist < snapThreshold.value) position = closest ?? position;
6386
- if (axis === "x") box.left = position - offset;
6387
- else box.top = position - offset;
6388
- }
6389
- };
6390
- Object.assign(editor, {
6391
- snappers,
6392
- registerSnapper,
6393
- unregisterSnapper,
6394
- snap
6395
- });
6396
- }),
6397
- defineMixin((editor) => {
6398
- const { isElement, frames, frameThumbs, log, fonts, runExclusiveRender } = editor;
6399
- async function snapshot() {
6400
- frameThumbs.value = frames.value.map(() => ({
6401
- instanceId: -1,
6402
- width: 0,
6403
- height: 0,
6404
- url: ""
6405
- }));
6406
- for (let i = 0; i < frames.value.length; i++) await captureFrameScreenshot(i);
6407
- }
6408
- async function captureElementScreenshot(element) {
6409
- await editor.waitUntilFontLoad();
6410
- let data;
6411
- if (isElement(element)) data = element.toJSON();
6412
- else data = { ...element };
6413
- data.style ??= {};
6414
- data.style.top = 0;
6415
- data.style.left = 0;
6416
- return await runExclusiveRender(() => render({
6417
- width: data.style.width,
6418
- height: data.style.height,
6419
- fonts,
6420
- data
6421
- }));
6422
- }
6423
- async function captureFrameScreenshot(index) {
6424
- const frame = frames.value[index];
6425
- if (frame) {
6426
- const canvas = await captureElementScreenshot(frame);
6427
- frameThumbs.value[index] = {
6428
- instanceId: frame.instanceId,
6429
- width: canvas.width,
6430
- height: canvas.height,
6431
- url: canvas.toDataURL()
6432
- };
6433
- log("captureFrameScreenshot", index);
6434
- }
6435
- }
6436
- Object.assign(editor, {
6437
- snapshot,
6438
- captureElementScreenshot,
6439
- captureFrameScreenshot
6440
- });
6946
+ http_default,
6947
+ loader_default,
6948
+ snapper_default,
6949
+ snapshot_default,
6950
+ defineMixin((_editor, options) => {
6951
+ return {
6952
+ activeStrategy: options.activeStrategy ?? defaultActiveStrategy,
6953
+ doubleclickStrategy: options.doubleclickStrategy ?? defaultDoubleclickStrategy,
6954
+ hoverStrategy: options.hoverStrategy ?? defaultHoverStrategy,
6955
+ resizeStrategy: options.resizeStrategy
6956
+ };
6441
6957
  }),
6442
6958
  defineMixin((editor) => {
6443
6959
  const { state } = editor;
@@ -6936,7 +7452,7 @@ var doc_default = definePlugin((editor, options) => {
6936
7452
  //#endregion
6937
7453
  //#region src/plugins/edit.ts
6938
7454
  var edit_default = definePlugin((editor, options) => {
6939
- const { state, selection, exec, canLoad, load, addElements, hoverElement, to, exporters } = editor;
7455
+ const { state, selection, exec, canLoad, load, addElements, hoverElement, to, exporters, renderEngine } = editor;
6940
7456
  const copiedData = ref();
6941
7457
  const useClipboard = options.clipboard !== false && SUPPORTS_CLIPBOARD;
6942
7458
  const cancel = () => {
@@ -6944,6 +7460,19 @@ var edit_default = definePlugin((editor, options) => {
6944
7460
  };
6945
7461
  const _delete = () => {
6946
7462
  if (selection.value.length) {
7463
+ const removed = /* @__PURE__ */ new Set();
7464
+ const collect = (node) => {
7465
+ removed.add(node.id);
7466
+ node.children?.forEach(collect);
7467
+ };
7468
+ selection.value.forEach(collect);
7469
+ const nodeMap = renderEngine.value.nodeMap;
7470
+ const danglingConnections = [];
7471
+ nodeMap?.forEach((node) => {
7472
+ const conn = node.connection;
7473
+ if (!removed.has(node.id) && conn?.isValid?.() && (removed.has(conn.start?.id) || removed.has(conn.end?.id))) danglingConnections.push(node);
7474
+ });
7475
+ danglingConnections.forEach((node) => node.remove());
6947
7476
  selection.value.forEach((node) => {
6948
7477
  node.remove();
6949
7478
  });
@@ -7365,6 +7894,7 @@ var aliases = {
7365
7894
  mouseLeftClick: "M13 9V1.07A8.01 8.01 0 0 1 19.75 7c.16.64.25 1.31.25 2zm4.66-2c-.48-1.35-1.43-2.5-2.66-3.19V7zM6 15v-2h12v2c0 1.59-.63 3.12-1.76 4.24A5.97 5.97 0 0 1 12 21a5.97 5.97 0 0 1-4.24-1.76A5.97 5.97 0 0 1 6 15m-2 0c0 2.12.84 4.16 2.34 5.66S9.88 23 12 23s4.16-.84 5.66-2.34S20 17.12 20 15v-4H4zm7-6V1.07C7.06 1.56 4 4.92 4 9z",
7366
7895
  mouseRightClick: "M13 9V1.07c3.94.49 7 3.85 7 7.93zm-2 0V1.07A8.01 8.01 0 0 0 4.25 7C4.09 7.64 4 8.31 4 9zM6.34 7C6.82 5.65 7.78 4.5 9 3.81V7zM6 15v-2h12v2c0 1.59-.63 3.12-1.76 4.24A5.97 5.97 0 0 1 12 21a5.97 5.97 0 0 1-4.24-1.76A5.97 5.97 0 0 1 6 15m-2 0c0 2.12.84 4.16 2.34 5.66S9.88 23 12 23s4.16-.84 5.66-2.34S20 17.12 20 15v-4H4z",
7367
7896
  check: "M21 7L9 19l-5.5-5.5l1.41-1.41L9 16.17L19.59 5.59z",
7897
+ plus: "M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6z",
7368
7898
  collapse: "m12 17.4l-3.9 3.9q-.275.275-.7.275t-.7-.275t-.275-.7t.275-.7l3.875-3.875q.575-.575 1.425-.575t1.425.575L17.3 19.9q.275.275.275.7t-.275.7t-.7.275t-.7-.275zm0-10.8l3.9-3.9q.275-.275.7-.275t.7.275t.275.7t-.275.7l-3.875 3.875Q12.85 8.55 12 8.55t-1.425-.575L6.7 4.1q-.275-.275-.275-.7t.275-.7t.7-.275t.7.275z",
7369
7899
  frame: "M17 9v6H7V9zm2-6h-2v3h2zM7 3H5v3h2zm16 4h-3v2h3zm-4 0H5v10h14zM4 7H1v2h3zm19 8h-3v2h3zM4 15H1v2h3zm15 3h-2v3h2zM7 18H5v3h2z",
7370
7900
  slice: "M20.802 4.221a2.166 2.166 0 0 0-3.062 0L2.24 19.72l.001.001A.75.75 0 0 0 2.773 21h8.125a2.25 2.25 0 0 0 2.25-2.25v-3.812l7.654-7.654a2.166 2.166 0 0 0 0-3.063m-7.654 8.596v-1.883L18.8 5.282a.665.665 0 1 1 .941.941zM4.584 19.5l7.064-7.064v6.314a.75.75 0 0 1-.75.75z",
@@ -7882,43 +8412,6 @@ function useOverlay() {
7882
8412
  return item;
7883
8413
  }
7884
8414
  //#endregion
7885
- //#region src/composables/strategy.ts
7886
- var makeMceStrategyProps = propsFactory({
7887
- resizeStrategy: Function,
7888
- activeStrategy: Function,
7889
- doubleclickStrategy: Function,
7890
- hoverStrategy: Function
7891
- }, "makeMceStrategyProps");
7892
- var defaultActiveStrategy = (context) => {
7893
- const { element, editor } = context;
7894
- if (!element) return;
7895
- const { isRootNode, inEditorIs, isElement, elementSelection } = editor;
7896
- const activeElement = elementSelection.value[0];
7897
- const cb = (node) => {
7898
- const parent = node.parent;
7899
- if (isElement(node) && (node.equal(activeElement) || parent?.equal(activeElement) || parent?.equal(activeElement?.parent) || parent && inEditorIs(parent, "Frame") && parent.parent && isRootNode(parent.parent) || parent && isRootNode(parent))) return true;
7900
- return false;
7901
- };
7902
- if (cb(element)) return element;
7903
- return element.findAncestor(cb);
7904
- };
7905
- var defaultDoubleclickStrategy = (context) => {
7906
- context.editor.exec("enter");
7907
- };
7908
- var defaultHoverStrategy = (context) => {
7909
- const { element, editor } = context;
7910
- if (!element) return;
7911
- const { isRootNode, inEditorIs, isElement, elementSelection } = editor;
7912
- const activeElement = elementSelection.value[0];
7913
- const cb = (node) => {
7914
- const parent = node.parent;
7915
- if (isElement(node) && (node.equal(activeElement) || parent?.equal(activeElement) || parent?.equal(activeElement?.parent) || parent && inEditorIs(parent, "Frame") && parent.parent && isRootNode(parent.parent) || parent && isRootNode(parent))) return true;
7916
- return false;
7917
- };
7918
- if (cb(element)) return element;
7919
- return element.findAncestor(cb);
7920
- };
7921
- //#endregion
7922
8415
  //#region src/components/Frame.vue
7923
8416
  var Frame_default = /* @__PURE__ */ defineComponent({
7924
8417
  __name: "Frame",
@@ -7976,7 +8469,7 @@ var Frame_default = /* @__PURE__ */ defineComponent({
7976
8469
  });
7977
8470
  //#endregion
7978
8471
  //#region src/components/Frames.vue?vue&type=script&setup=true&lang.ts
7979
- var _hoisted_1$30 = { class: "m-frames" };
8472
+ var _hoisted_1$31 = { class: "m-frames" };
7980
8473
  //#endregion
7981
8474
  //#region src/components/Frames.vue
7982
8475
  var Frames_default = /* @__PURE__ */ defineComponent({
@@ -7985,7 +8478,7 @@ var Frames_default = /* @__PURE__ */ defineComponent({
7985
8478
  const { frames, getConfigRef } = useEditor();
7986
8479
  const config = getConfigRef("canvas.frame");
7987
8480
  return (_ctx, _cache) => {
7988
- return openBlock(), createElementBlock("div", _hoisted_1$30, [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(frames), (frame, key) => {
8481
+ return openBlock(), createElementBlock("div", _hoisted_1$31, [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(frames), (frame, key) => {
7989
8482
  return openBlock(), createBlock(Frame_default, {
7990
8483
  key,
7991
8484
  "model-value": frame,
@@ -8131,7 +8624,7 @@ var history_default = definePlugin((editor) => {
8131
8624
  });
8132
8625
  //#endregion
8133
8626
  //#region src/components/Hover.vue?vue&type=script&setup=true&lang.ts
8134
- var _hoisted_1$29 = ["data-name"];
8627
+ var _hoisted_1$30 = ["data-name"];
8135
8628
  //#endregion
8136
8629
  //#region src/components/Hover.vue
8137
8630
  var Hover_default = /* @__PURE__ */ defineComponent({
@@ -8150,7 +8643,7 @@ var Hover_default = /* @__PURE__ */ defineComponent({
8150
8643
  borderRadius: `${(unref(hoverElement).style.borderRadius ?? 0) * unref(camera).zoom.x}px`,
8151
8644
  ...hoverElementObb.value.toCssStyle()
8152
8645
  })
8153
- }, null, 12, _hoisted_1$29)) : createCommentVNode("", true);
8646
+ }, null, 12, _hoisted_1$30)) : createCommentVNode("", true);
8154
8647
  };
8155
8648
  }
8156
8649
  });
@@ -8419,10 +8912,10 @@ var Btn_default = /* @__PURE__ */ defineComponent({
8419
8912
  });
8420
8913
  //#endregion
8421
8914
  //#region src/components/Layer.vue?vue&type=script&setup=true&lang.ts
8422
- var _hoisted_1$28 = ["data-id"];
8423
- var _hoisted_2$14 = { class: "m-layer__content" };
8424
- var _hoisted_3$13 = { class: "m-layer__prepend" };
8425
- var _hoisted_4$7 = {
8915
+ var _hoisted_1$29 = ["data-id"];
8916
+ var _hoisted_2$15 = { class: "m-layer__content" };
8917
+ var _hoisted_3$14 = { class: "m-layer__prepend" };
8918
+ var _hoisted_4$8 = {
8426
8919
  key: 0,
8427
8920
  class: "m-layer__name"
8428
8921
  };
@@ -8566,8 +9059,8 @@ var Layer_default = /* @__PURE__ */ defineComponent({
8566
9059
  }, [
8567
9060
  _cache[5] || (_cache[5] = createElementVNode("span", { class: "m-layer__underlay" }, null, -1)),
8568
9061
  _cache[6] || (_cache[6] = createElementVNode("span", { class: "m-layer__overlay" }, null, -1)),
8569
- createElementVNode("div", _hoisted_2$14, [
8570
- createElementVNode("div", _hoisted_3$13, [childrenLength.value ? (openBlock(), createBlock(unref(Icon_default), {
9062
+ createElementVNode("div", _hoisted_2$15, [
9063
+ createElementVNode("div", _hoisted_3$14, [childrenLength.value ? (openBlock(), createBlock(unref(Icon_default), {
8571
9064
  key: 0,
8572
9065
  class: "m-layer__arrow",
8573
9066
  icon: "$arrowRight",
@@ -8578,7 +9071,7 @@ var Layer_default = /* @__PURE__ */ defineComponent({
8578
9071
  class: "m-layer__thumbnail",
8579
9072
  onDblclick: onDblclickThumbnail
8580
9073
  }, [createVNode(unref(Icon_default), { icon: unref(thumbnailIcon) }, null, 8, ["icon"])], 32),
8581
- props.root ? (openBlock(), createElementBlock("div", _hoisted_4$7, toDisplayString(unref(t)("layers")), 1)) : (openBlock(), createElementBlock("div", {
9074
+ props.root ? (openBlock(), createElementBlock("div", _hoisted_4$8, toDisplayString(unref(t)("layers")), 1)) : (openBlock(), createElementBlock("div", {
8582
9075
  key: 1,
8583
9076
  class: "m-layer__name",
8584
9077
  onDblclick: onDblclickName
@@ -8625,7 +9118,7 @@ var Layer_default = /* @__PURE__ */ defineComponent({
8625
9118
  _: 1
8626
9119
  }, 8, ["class"])], 64))], 2)
8627
9120
  ])
8628
- ], 46, _hoisted_1$28), opened.value ? (openBlock(true), createElementBlock(Fragment, { key: 0 }, renderList(childrenLength.value, (i) => {
9121
+ ], 46, _hoisted_1$29), opened.value ? (openBlock(true), createElementBlock(Fragment, { key: 0 }, renderList(childrenLength.value, (i) => {
8629
9122
  return openBlock(), createBlock(_component_MceLayer, {
8630
9123
  key: i,
8631
9124
  node: children.value[childrenLength.value - i],
@@ -8642,8 +9135,8 @@ var Layer_default = /* @__PURE__ */ defineComponent({
8642
9135
  });
8643
9136
  //#endregion
8644
9137
  //#region src/components/Layers.vue?vue&type=script&setup=true&lang.ts
8645
- var _hoisted_1$27 = { class: "m-layers" };
8646
- var _hoisted_2$13 = { class: "m-layers__wrapper" };
9138
+ var _hoisted_1$28 = { class: "m-layers" };
9139
+ var _hoisted_2$14 = { class: "m-layers__wrapper" };
8647
9140
  //#endregion
8648
9141
  //#region src/components/Layers.vue
8649
9142
  var Layers_default = /* @__PURE__ */ defineComponent({
@@ -8677,7 +9170,7 @@ var Layers_default = /* @__PURE__ */ defineComponent({
8677
9170
  layerScrollIntoView();
8678
9171
  });
8679
9172
  return (_ctx, _cache) => {
8680
- return openBlock(), createElementBlock("div", _hoisted_1$27, [createElementVNode("div", _hoisted_2$13, [createVNode(Layer_default, {
9173
+ return openBlock(), createElementBlock("div", _hoisted_1$28, [createElementVNode("div", _hoisted_2$14, [createVNode(Layer_default, {
8681
9174
  root: true,
8682
9175
  node: unref(root),
8683
9176
  opened: true
@@ -8712,13 +9205,13 @@ var _plugin_vue_export_helper_default = (sfc, props) => {
8712
9205
  //#endregion
8713
9206
  //#region src/components/MadeWith.vue
8714
9207
  var _sfc_main = {};
8715
- var _hoisted_1$26 = {
9208
+ var _hoisted_1$27 = {
8716
9209
  class: "m-made-with",
8717
9210
  href: "https://github.com/qq15725/mce",
8718
9211
  target: "_blank"
8719
9212
  };
8720
9213
  function _sfc_render(_ctx, _cache) {
8721
- return openBlock(), createElementBlock("a", _hoisted_1$26, [..._cache[0] || (_cache[0] = [createElementVNode("div", null, "MADE WITH", -1), createElementVNode("div", null, "MCE", -1)])]);
9214
+ return openBlock(), createElementBlock("a", _hoisted_1$27, [..._cache[0] || (_cache[0] = [createElementVNode("div", null, "MADE WITH", -1), createElementVNode("div", null, "MCE", -1)])]);
8722
9215
  }
8723
9216
  var MadeWith_default = /* @__PURE__ */ _plugin_vue_export_helper_default(_sfc_main, [["render", _sfc_render]]);
8724
9217
  //#endregion
@@ -8740,7 +9233,7 @@ var madeWith_default = definePlugin((editor) => {
8740
9233
  });
8741
9234
  //#endregion
8742
9235
  //#region src/components/MemoryManager.vue?vue&type=script&setup=true&lang.ts
8743
- var _hoisted_1$25 = { class: "m-manage-memory" };
9236
+ var _hoisted_1$26 = { class: "m-manage-memory" };
8744
9237
  //#endregion
8745
9238
  //#region src/components/MemoryManager.vue
8746
9239
  var MemoryManager_default = /* @__PURE__ */ defineComponent({
@@ -8773,7 +9266,7 @@ var MemoryManager_default = /* @__PURE__ */ defineComponent({
8773
9266
  });
8774
9267
  onBeforeUnmount(() => timer && clearInterval(timer));
8775
9268
  return (_ctx, _cache) => {
8776
- return openBlock(), createElementBlock("div", _hoisted_1$25, [_cache[0] || (_cache[0] = createElementVNode("div", null, "Total memory used", -1)), createElementVNode("div", null, toDisplayString(humanBytes(used.value)), 1)]);
9269
+ return openBlock(), createElementBlock("div", _hoisted_1$26, [_cache[0] || (_cache[0] = createElementVNode("div", null, "Total memory used", -1)), createElementVNode("div", null, toDisplayString(humanBytes(used.value)), 1)]);
8777
9270
  };
8778
9271
  }
8779
9272
  });
@@ -8897,18 +9390,18 @@ var Overlay_default = /* @__PURE__ */ defineComponent({
8897
9390
  });
8898
9391
  //#endregion
8899
9392
  //#region src/components/shared/Menu.vue?vue&type=script&setup=true&lang.ts
8900
- var _hoisted_1$24 = ["onMouseenter"];
8901
- var _hoisted_2$12 = ["onClick"];
8902
- var _hoisted_3$12 = {
9393
+ var _hoisted_1$25 = ["onMouseenter"];
9394
+ var _hoisted_2$13 = ["onClick"];
9395
+ var _hoisted_3$13 = {
8903
9396
  key: 0,
8904
9397
  class: "m-list-item__checked"
8905
9398
  };
8906
- var _hoisted_4$6 = {
9399
+ var _hoisted_4$7 = {
8907
9400
  key: 1,
8908
9401
  class: "m-list-item__prepend"
8909
9402
  };
8910
- var _hoisted_5$4 = { class: "m-list-item__title" };
8911
- var _hoisted_6$3 = {
9403
+ var _hoisted_5$5 = { class: "m-list-item__title" };
9404
+ var _hoisted_6$4 = {
8912
9405
  key: 2,
8913
9406
  class: "m-list-item__kbd"
8914
9407
  };
@@ -9024,18 +9517,18 @@ var Menu_default = /* @__PURE__ */ defineComponent({
9024
9517
  class: normalizeClass(["m-list-item", [item.disabled && "m-list-item--disabled", opened.value === index && "m-list-item--opened"]]),
9025
9518
  onClick: (e) => onClickItem(item, index, e)
9026
9519
  }, [
9027
- hasPrepend.value ? (openBlock(), createElementBlock("div", _hoisted_3$12, [item.checked ? (openBlock(), createBlock(unref(Icon_default), {
9520
+ hasPrepend.value ? (openBlock(), createElementBlock("div", _hoisted_3$13, [item.checked ? (openBlock(), createBlock(unref(Icon_default), {
9028
9521
  key: 0,
9029
9522
  icon: "$check"
9030
9523
  })) : createCommentVNode("", true)])) : createCommentVNode("", true),
9031
- _ctx.$slots.prepend ? (openBlock(), createElementBlock("div", _hoisted_4$6, [renderSlot(_ctx.$slots, "prepend", { item })])) : createCommentVNode("", true),
9032
- createElementVNode("div", _hoisted_5$4, [renderSlot(_ctx.$slots, "title", { item }, () => [createTextVNode(toDisplayString(item.key), 1)])]),
9033
- _ctx.$slots.kbd ? (openBlock(), createElementBlock("div", _hoisted_6$3, [renderSlot(_ctx.$slots, "kbd", { item })])) : createCommentVNode("", true),
9524
+ _ctx.$slots.prepend ? (openBlock(), createElementBlock("div", _hoisted_4$7, [renderSlot(_ctx.$slots, "prepend", { item })])) : createCommentVNode("", true),
9525
+ createElementVNode("div", _hoisted_5$5, [renderSlot(_ctx.$slots, "title", { item }, () => [createTextVNode(toDisplayString(item.key), 1)])]),
9526
+ _ctx.$slots.kbd ? (openBlock(), createElementBlock("div", _hoisted_6$4, [renderSlot(_ctx.$slots, "kbd", { item })])) : createCommentVNode("", true),
9034
9527
  item.children?.length || _ctx.$slots.append ? (openBlock(), createElementBlock("div", _hoisted_7$3, [renderSlot(_ctx.$slots, "append", { item }), item.children?.length ? (openBlock(), createBlock(unref(Icon_default), {
9035
9528
  key: 0,
9036
9529
  icon: "$arrowRight"
9037
9530
  })) : createCommentVNode("", true)])) : createCommentVNode("", true)
9038
- ], 10, _hoisted_2$12)], 40, _hoisted_1$24))], 64);
9531
+ ], 10, _hoisted_2$13)], 40, _hoisted_1$25))], 64);
9039
9532
  }), 128)), opened.value > -1 && __props.items?.[opened.value]?.children?.length ? (openBlock(), createBlock(_component_MceMenu, {
9040
9533
  key: 0,
9041
9534
  "open-on-hover": "",
@@ -9183,7 +9676,7 @@ var ContextMenu_default = /* @__PURE__ */ defineComponent({
9183
9676
  //#endregion
9184
9677
  //#region src/plugins/menu.ts
9185
9678
  var menu_default = definePlugin((editor, options) => {
9186
- const { canUndo, canRedo, selection, elementSelection, textSelection, config, exporters, components, isElement, exec } = editor;
9679
+ const { canUndo, canRedo, selection, elementSelection, textSelection, config, exporters, components, isElement, exec, mode } = editor;
9187
9680
  const { customContextMenu } = options;
9188
9681
  const hasSelected = computed(() => selection.value.length > 0);
9189
9682
  const exportMenu = computed(() => ({
@@ -9213,6 +9706,18 @@ var menu_default = definePlugin((editor, options) => {
9213
9706
  children: [...exporters.values()].filter((v) => Boolean(v.copyAs)).map((v) => ({ key: `copyAs:${v.name}` }))
9214
9707
  }));
9215
9708
  const nodeMenu = computed(() => [{ key: "addSubNode" }]);
9709
+ const modeMenu = computed(() => ({
9710
+ key: "mode",
9711
+ children: [{
9712
+ key: "mode:canvas",
9713
+ checked: mode.value === "canvas",
9714
+ handle: () => mode.value = "canvas"
9715
+ }, {
9716
+ key: "mode:workflow",
9717
+ checked: mode.value === "workflow",
9718
+ handle: () => mode.value = "workflow"
9719
+ }]
9720
+ }));
9216
9721
  const editMenus1 = computed(() => [
9217
9722
  {
9218
9723
  key: "copy",
@@ -9521,6 +10026,8 @@ var menu_default = definePlugin((editor, options) => {
9521
10026
  else return [
9522
10027
  { key: "paste" },
9523
10028
  { type: "divider" },
10029
+ modeMenu.value,
10030
+ { type: "divider" },
9524
10031
  ...mainMenu.value,
9525
10032
  { type: "divider" },
9526
10033
  exportMenu.value
@@ -9545,9 +10052,9 @@ var menu_default = definePlugin((editor, options) => {
9545
10052
  });
9546
10053
  //#endregion
9547
10054
  //#region src/components/Creator.vue?vue&type=script&setup=true&lang.ts
9548
- var _hoisted_1$23 = { class: "m-creator" };
9549
- var _hoisted_2$11 = { class: "m-creator__tree" };
9550
- var _hoisted_3$11 = { class: "m-creator__actions" };
10055
+ var _hoisted_1$24 = { class: "m-creator" };
10056
+ var _hoisted_2$12 = { class: "m-creator__tree" };
10057
+ var _hoisted_3$12 = { class: "m-creator__actions" };
9551
10058
  //#endregion
9552
10059
  //#region src/components/Creator.vue
9553
10060
  var Creator_default = /* @__PURE__ */ defineComponent({
@@ -9618,12 +10125,12 @@ var Creator_default = /* @__PURE__ */ defineComponent({
9618
10125
  })];
9619
10126
  }
9620
10127
  return (_ctx, _cache) => {
9621
- return openBlock(), createElementBlock("div", _hoisted_1$23, [createElementVNode("div", _hoisted_2$11, [(openBlock(true), createElementBlock(Fragment, null, renderList(tree.value, (node, index) => {
10128
+ return openBlock(), createElementBlock("div", _hoisted_1$24, [createElementVNode("div", _hoisted_2$12, [(openBlock(true), createElementBlock(Fragment, null, renderList(tree.value, (node, index) => {
9622
10129
  return openBlock(), createBlock(CreatorNode, {
9623
10130
  key: index,
9624
10131
  node
9625
10132
  }, null, 8, ["node"]);
9626
- }), 128))]), createElementVNode("div", _hoisted_3$11, [createVNode(Btn_default, { onClick: cancel }, {
10133
+ }), 128))]), createElementVNode("div", _hoisted_3$12, [createVNode(Btn_default, { onClick: cancel }, {
9627
10134
  default: withCtx(() => [createTextVNode(toDisplayString(unref(t)("cancel")), 1)]),
9628
10135
  _: 1
9629
10136
  }), createVNode(Btn_default, { onClick: create }, {
@@ -9798,12 +10305,12 @@ var pen_default = definePlugin((editor) => {
9798
10305
  });
9799
10306
  //#endregion
9800
10307
  //#region src/components/shared/Tooltip.vue?vue&type=script&setup=true&lang.ts
9801
- var _hoisted_1$22 = {
10308
+ var _hoisted_1$23 = {
9802
10309
  key: 0,
9803
10310
  class: "m-tooltip__arrow"
9804
10311
  };
9805
- var _hoisted_2$10 = { class: "m-tooltip__content" };
9806
- var _hoisted_3$10 = {
10312
+ var _hoisted_2$11 = { class: "m-tooltip__content" };
10313
+ var _hoisted_3$11 = {
9807
10314
  key: 0,
9808
10315
  class: "m-tooltip__kbd"
9809
10316
  };
@@ -9846,7 +10353,7 @@ var Tooltip_default = /* @__PURE__ */ defineComponent({
9846
10353
  target: props.target,
9847
10354
  attach: props.attach
9848
10355
  }, createSlots({
9849
- default: withCtx(() => [isActive.value ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [__props.showArrow ? (openBlock(), createElementBlock("div", _hoisted_1$22)) : createCommentVNode("", true), createElementVNode("div", _hoisted_2$10, [renderSlot(_ctx.$slots, "default"), _ctx.$slots.kbd ? (openBlock(), createElementBlock("div", _hoisted_3$10, [renderSlot(_ctx.$slots, "kbd")])) : createCommentVNode("", true)])], 64)) : createCommentVNode("", true)]),
10356
+ default: withCtx(() => [isActive.value ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [__props.showArrow ? (openBlock(), createElementBlock("div", _hoisted_1$23)) : createCommentVNode("", true), createElementVNode("div", _hoisted_2$11, [renderSlot(_ctx.$slots, "default"), _ctx.$slots.kbd ? (openBlock(), createElementBlock("div", _hoisted_3$11, [renderSlot(_ctx.$slots, "kbd")])) : createCommentVNode("", true)])], 64)) : createCommentVNode("", true)]),
9850
10357
  _: 2
9851
10358
  }, [_ctx.$slots.activator ? {
9852
10359
  name: "activator",
@@ -9869,13 +10376,13 @@ var Tooltip_default = /* @__PURE__ */ defineComponent({
9869
10376
  });
9870
10377
  //#endregion
9871
10378
  //#region src/components/shared/Ruler.vue?vue&type=script&setup=true&lang.ts
9872
- var _hoisted_1$21 = ["width", "height"];
9873
- var _hoisted_2$9 = [
10379
+ var _hoisted_1$22 = ["width", "height"];
10380
+ var _hoisted_2$10 = [
9874
10381
  "onDblclick",
9875
10382
  "onMousedown",
9876
10383
  "onMousemove"
9877
10384
  ];
9878
- var _hoisted_3$9 = { style: {
10385
+ var _hoisted_3$10 = { style: {
9879
10386
  "font-size": "0.75rem",
9880
10387
  "text-wrap": "nowrap"
9881
10388
  } };
@@ -10146,7 +10653,7 @@ var Ruler_default = /* @__PURE__ */ defineComponent({
10146
10653
  class: "m-ruler__canvas",
10147
10654
  width: props.size,
10148
10655
  height: props.size
10149
- }, null, 8, _hoisted_1$21)], 16)), [[unref(vResizeObserver), unref(resize)]]),
10656
+ }, null, 8, _hoisted_1$22)], 16)), [[unref(vResizeObserver), unref(resize)]]),
10150
10657
  (openBlock(true), createElementBlock(Fragment, null, renderList(lines.value, (item, index) => {
10151
10658
  return openBlock(), createElementBlock("div", {
10152
10659
  key: index,
@@ -10167,7 +10674,7 @@ var Ruler_default = /* @__PURE__ */ defineComponent({
10167
10674
  onMousedown: ($event) => onReflineMousedown($event, index),
10168
10675
  onMousemove: (e) => updateTip(e, item),
10169
10676
  onMouseleave: onLeave
10170
- }, null, 46, _hoisted_2$9);
10677
+ }, null, 46, _hoisted_2$10);
10171
10678
  }), 128)),
10172
10679
  createVNode(Tooltip_default, {
10173
10680
  "model-value": !!tipText.value,
@@ -10175,7 +10682,7 @@ var Ruler_default = /* @__PURE__ */ defineComponent({
10175
10682
  offset: 24,
10176
10683
  location: props.vertical ? "bottom" : "right"
10177
10684
  }, {
10178
- default: withCtx(() => [createElementVNode("div", _hoisted_3$9, toDisplayString(tipText.value), 1)]),
10685
+ default: withCtx(() => [createElementVNode("div", _hoisted_3$10, toDisplayString(tipText.value), 1)]),
10179
10686
  _: 1
10180
10687
  }, 8, [
10181
10688
  "model-value",
@@ -10188,7 +10695,7 @@ var Ruler_default = /* @__PURE__ */ defineComponent({
10188
10695
  });
10189
10696
  //#endregion
10190
10697
  //#region src/components/Rulers.vue?vue&type=script&setup=true&lang.ts
10191
- var _hoisted_1$20 = { class: "m-rulers" };
10698
+ var _hoisted_1$21 = { class: "m-rulers" };
10192
10699
  //#endregion
10193
10700
  //#region src/components/Rulers.vue
10194
10701
  var Rulers_default = /* @__PURE__ */ defineComponent({
@@ -10203,7 +10710,7 @@ var Rulers_default = /* @__PURE__ */ defineComponent({
10203
10710
  const { getConfigRef, camera, selectionAabbInDrawboard } = useEditor();
10204
10711
  const config = getConfigRef("ui.ruler");
10205
10712
  return (_ctx, _cache) => {
10206
- return openBlock(), createElementBlock("div", _hoisted_1$20, [
10713
+ return openBlock(), createElementBlock("div", _hoisted_1$21, [
10207
10714
  createVNode(Ruler_default, {
10208
10715
  modelValue: refLines.value.x,
10209
10716
  "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => refLines.value.x = $event),
@@ -10317,7 +10824,7 @@ var saveAs_default = definePlugin((editor) => {
10317
10824
  });
10318
10825
  //#endregion
10319
10826
  //#region src/components/shared/Scrollbar.vue?vue&type=script&setup=true&lang.ts
10320
- var _hoisted_1$19 = {
10827
+ var _hoisted_1$20 = {
10321
10828
  ref: "trackTplRef",
10322
10829
  class: "m-scrollbar__track"
10323
10830
  };
@@ -10400,7 +10907,7 @@ var Scrollbar_default = /* @__PURE__ */ defineComponent({
10400
10907
  [props.vertical ? "width" : "height"]: `${props.size}px`,
10401
10908
  [props.vertical ? "top" : "left"]: `${props.offset}px`
10402
10909
  })
10403
- }, [createElementVNode("div", _hoisted_1$19, [createElementVNode("div", {
10910
+ }, [createElementVNode("div", _hoisted_1$20, [createElementVNode("div", {
10404
10911
  ref: "thumbTplRef",
10405
10912
  class: normalizeClass(["m-scrollbar__thumb", { "m-scrollbar__thumb--active": isActive.value }]),
10406
10913
  style: normalizeStyle({
@@ -10416,7 +10923,7 @@ var Scrollbar_default = /* @__PURE__ */ defineComponent({
10416
10923
  });
10417
10924
  //#endregion
10418
10925
  //#region src/components/Scrollbars.vue?vue&type=script&setup=true&lang.ts
10419
- var _hoisted_1$18 = { class: "m-scrollbars" };
10926
+ var _hoisted_1$19 = { class: "m-scrollbars" };
10420
10927
  //#endregion
10421
10928
  //#region src/components/Scrollbars.vue
10422
10929
  var Scrollbars_default = /* @__PURE__ */ defineComponent({
@@ -10429,7 +10936,7 @@ var Scrollbars_default = /* @__PURE__ */ defineComponent({
10429
10936
  const props = __props;
10430
10937
  const { camera, rootAabb } = useEditor();
10431
10938
  return (_ctx, _cache) => {
10432
- return openBlock(), createElementBlock("div", _hoisted_1$18, [createVNode(Scrollbar_default, mergeProps(props, {
10939
+ return openBlock(), createElementBlock("div", _hoisted_1$19, [createVNode(Scrollbar_default, mergeProps(props, {
10433
10940
  modelValue: unref(camera).position.y,
10434
10941
  "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => unref(camera).position.y = $event),
10435
10942
  vertical: "",
@@ -10564,22 +11071,22 @@ var ScrollToSelection_default = /* @__PURE__ */ defineComponent({
10564
11071
  });
10565
11072
  //#endregion
10566
11073
  //#region src/components/shared/Transform.vue?vue&type=script&setup=true&lang.ts
10567
- var _hoisted_1$17 = ["rx", "ry"];
10568
- var _hoisted_2$8 = { "pointer-events": "none" };
10569
- var _hoisted_3$8 = [
11074
+ var _hoisted_1$18 = ["rx", "ry"];
11075
+ var _hoisted_2$9 = { "pointer-events": "none" };
11076
+ var _hoisted_3$9 = [
10570
11077
  "x",
10571
11078
  "y",
10572
11079
  "width",
10573
11080
  "height",
10574
11081
  "aria-label"
10575
11082
  ];
10576
- var _hoisted_4$5 = [
11083
+ var _hoisted_4$6 = [
10577
11084
  "cx",
10578
11085
  "cy",
10579
11086
  "r",
10580
11087
  "aria-label"
10581
11088
  ];
10582
- var _hoisted_5$3 = [
11089
+ var _hoisted_5$4 = [
10583
11090
  "x",
10584
11091
  "y",
10585
11092
  "width",
@@ -10588,7 +11095,7 @@ var _hoisted_5$3 = [
10588
11095
  "rx",
10589
11096
  "ry"
10590
11097
  ];
10591
- var _hoisted_6$2 = ["transform"];
11098
+ var _hoisted_6$3 = ["transform"];
10592
11099
  var _hoisted_7$2 = { "pointer-events": "all" };
10593
11100
  var _hoisted_8$2 = [
10594
11101
  "x",
@@ -11201,9 +11708,9 @@ var Transform_default = /* @__PURE__ */ defineComponent({
11201
11708
  fill: "none",
11202
11709
  rx: model.value.borderRadius,
11203
11710
  ry: model.value.borderRadius
11204
- }, null, 8, _hoisted_1$17),
11711
+ }, null, 8, _hoisted_1$18),
11205
11712
  createVNode(Diagonal),
11206
- createElementVNode("g", _hoisted_2$8, [(openBlock(true), createElementBlock(Fragment, null, renderList(computedHandles.value, (handle, index) => {
11713
+ createElementVNode("g", _hoisted_2$9, [(openBlock(true), createElementBlock(Fragment, null, renderList(computedHandles.value, (handle, index) => {
11207
11714
  return openBlock(), createElementBlock(Fragment, { key: index }, [handle.shape ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [handle.shape === "rect" ? (openBlock(), createElementBlock("rect", {
11208
11715
  key: 0,
11209
11716
  x: handle.x,
@@ -11212,14 +11719,14 @@ var Transform_default = /* @__PURE__ */ defineComponent({
11212
11719
  height: handle.height,
11213
11720
  "aria-label": handle.type,
11214
11721
  class: "m-transform__handle"
11215
- }, null, 8, _hoisted_3$8)) : handle.width === handle.height ? (openBlock(), createElementBlock("circle", {
11722
+ }, null, 8, _hoisted_3$9)) : handle.width === handle.height ? (openBlock(), createElementBlock("circle", {
11216
11723
  key: 1,
11217
11724
  cx: handle.x + handle.width / 2,
11218
11725
  cy: handle.y + handle.width / 2,
11219
11726
  r: handle.width / 2,
11220
11727
  "aria-label": handle.type,
11221
11728
  class: "m-transform__handle"
11222
- }, null, 8, _hoisted_4$5)) : (openBlock(), createElementBlock("rect", {
11729
+ }, null, 8, _hoisted_4$6)) : (openBlock(), createElementBlock("rect", {
11223
11730
  key: 2,
11224
11731
  x: handle.x,
11225
11732
  y: handle.y,
@@ -11229,12 +11736,12 @@ var Transform_default = /* @__PURE__ */ defineComponent({
11229
11736
  rx: handle.width / 4,
11230
11737
  ry: handle.height / 4,
11231
11738
  class: "m-transform__handle"
11232
- }, null, 8, _hoisted_5$3))], 64)) : createCommentVNode("", true)], 64);
11739
+ }, null, 8, _hoisted_5$4))], 64)) : createCommentVNode("", true)], 64);
11233
11740
  }), 128)), __props.rotator ? (openBlock(), createElementBlock("g", {
11234
11741
  key: 0,
11235
11742
  transform: `matrix(1, 0, 0, 1, -32, ${model.value.height}) rotate(270 16 16)`,
11236
11743
  class: "m-transform__rotator"
11237
- }, [..._cache[0] || (_cache[0] = [createElementVNode("path", { d: "M22.4789 9.45728L25.9935 12.9942L22.4789 16.5283V14.1032C18.126 14.1502 14.6071 17.6737 14.5675 22.0283H17.05L13.513 25.543L9.97889 22.0283H12.5674C12.6071 16.5691 17.0214 12.1503 22.4789 12.1031L22.4789 9.45728Z" }, null, -1)])], 8, _hoisted_6$2)) : createCommentVNode("", true)]),
11744
+ }, [..._cache[0] || (_cache[0] = [createElementVNode("path", { d: "M22.4789 9.45728L25.9935 12.9942L22.4789 16.5283V14.1032C18.126 14.1502 14.6071 17.6737 14.5675 22.0283H17.05L13.513 25.543L9.97889 22.0283H12.5674C12.6071 16.5691 17.0214 12.1503 22.4789 12.1031L22.4789 9.45728Z" }, null, -1)])], 8, _hoisted_6$3)) : createCommentVNode("", true)]),
11238
11745
  createElementVNode("g", _hoisted_7$2, [(openBlock(true), createElementBlock(Fragment, null, renderList(computedHandles.value, (handle, index) => {
11239
11746
  return openBlock(), createElementBlock("rect", {
11240
11747
  key: index,
@@ -11262,7 +11769,7 @@ var Transform_default = /* @__PURE__ */ defineComponent({
11262
11769
  });
11263
11770
  //#endregion
11264
11771
  //#region src/components/shared/Cropper.vue?vue&type=script&setup=true&lang.ts
11265
- var _hoisted_1$16 = { class: "m-cropper" };
11772
+ var _hoisted_1$17 = { class: "m-cropper" };
11266
11773
  //#endregion
11267
11774
  //#region src/components/shared/Cropper.vue
11268
11775
  var Cropper_default = /* @__PURE__ */ defineComponent({
@@ -11461,7 +11968,7 @@ var Cropper_default = /* @__PURE__ */ defineComponent({
11461
11968
  onBeforeMount(() => emit("start"));
11462
11969
  onBeforeUnmount(() => emit("end"));
11463
11970
  return (_ctx, _cache) => {
11464
- return withDirectives((openBlock(), createElementBlock("div", _hoisted_1$16, [
11971
+ return withDirectives((openBlock(), createElementBlock("div", _hoisted_1$17, [
11465
11972
  createElementVNode("div", {
11466
11973
  class: "m-cropper__source",
11467
11974
  style: normalizeStyle(unref(boundingBoxToStyle)(sourceTransform.value))
@@ -11535,24 +12042,24 @@ var ForegroundCropper_default = /* @__PURE__ */ defineComponent({
11535
12042
  });
11536
12043
  //#endregion
11537
12044
  //#region src/components/PathEditor.vue?vue&type=script&setup=true&lang.ts
11538
- var _hoisted_1$15 = {
12045
+ var _hoisted_1$16 = {
11539
12046
  ref: "svgTpl",
11540
12047
  class: "m-path-editor",
11541
12048
  style: { overflow: "visible" }
11542
12049
  };
11543
- var _hoisted_2$7 = ["d"];
11544
- var _hoisted_3$7 = [
12050
+ var _hoisted_2$8 = ["d"];
12051
+ var _hoisted_3$8 = [
11545
12052
  "x1",
11546
12053
  "y1",
11547
12054
  "x2",
11548
12055
  "y2"
11549
12056
  ];
11550
- var _hoisted_4$4 = [
12057
+ var _hoisted_4$5 = [
11551
12058
  "cx",
11552
12059
  "cy",
11553
12060
  "onPointerdown"
11554
12061
  ];
11555
- var _hoisted_5$2 = [
12062
+ var _hoisted_5$3 = [
11556
12063
  "x",
11557
12064
  "y",
11558
12065
  "onPointerdown",
@@ -12240,12 +12747,12 @@ var PathEditor_default = /* @__PURE__ */ defineComponent({
12240
12747
  onUp();
12241
12748
  });
12242
12749
  return (_ctx, _cache) => {
12243
- return openBlock(), createElementBlock("svg", _hoisted_1$15, [
12750
+ return openBlock(), createElementBlock("svg", _hoisted_1$16, [
12244
12751
  createElementVNode("path", {
12245
12752
  class: "m-path-editor__hit",
12246
12753
  d: screenPath.value,
12247
12754
  onDblclick: onInsert
12248
- }, null, 40, _hoisted_2$7),
12755
+ }, null, 40, _hoisted_2$8),
12249
12756
  (openBlock(true), createElementBlock(Fragment, null, renderList(controls.value, (c, i) => {
12250
12757
  return openBlock(), createElementBlock("line", {
12251
12758
  key: `l${i}`,
@@ -12254,7 +12761,7 @@ var PathEditor_default = /* @__PURE__ */ defineComponent({
12254
12761
  y1: c.ay,
12255
12762
  x2: c.x,
12256
12763
  y2: c.y
12257
- }, null, 8, _hoisted_3$7);
12764
+ }, null, 8, _hoisted_3$8);
12258
12765
  }), 128)),
12259
12766
  (openBlock(true), createElementBlock(Fragment, null, renderList(controls.value, (c, i) => {
12260
12767
  return openBlock(), createElementBlock("circle", {
@@ -12264,7 +12771,7 @@ var PathEditor_default = /* @__PURE__ */ defineComponent({
12264
12771
  cy: c.y,
12265
12772
  r: "4",
12266
12773
  onPointerdown: ($event) => onDown($event, c.pi, c.ci, c.field)
12267
- }, null, 40, _hoisted_4$4);
12774
+ }, null, 40, _hoisted_4$5);
12268
12775
  }), 128)),
12269
12776
  (openBlock(true), createElementBlock(Fragment, null, renderList(anchors.value, (a, i) => {
12270
12777
  return openBlock(), createElementBlock("rect", {
@@ -12276,7 +12783,7 @@ var PathEditor_default = /* @__PURE__ */ defineComponent({
12276
12783
  height: "8",
12277
12784
  onPointerdown: ($event) => onDown($event, a.pi, a.ci, "xy"),
12278
12785
  onDblclick: withModifiers(($event) => toggleSmooth(a.pi, a.ci), ["stop"])
12279
- }, null, 42, _hoisted_5$2);
12786
+ }, null, 42, _hoisted_5$3);
12280
12787
  }), 128))
12281
12788
  ], 512);
12282
12789
  };
@@ -12284,7 +12791,7 @@ var PathEditor_default = /* @__PURE__ */ defineComponent({
12284
12791
  });
12285
12792
  //#endregion
12286
12793
  //#region src/components/Selection.vue?vue&type=script&setup=true&lang.ts
12287
- var _hoisted_1$14 = { class: "m-selection" };
12794
+ var _hoisted_1$15 = { class: "m-selection" };
12288
12795
  //#endregion
12289
12796
  //#region src/components/Selection.vue
12290
12797
  var Selection_default = /* @__PURE__ */ defineComponent({
@@ -12351,23 +12858,26 @@ var Selection_default = /* @__PURE__ */ defineComponent({
12351
12858
  emit("selectionTransformEnded", ctx);
12352
12859
  }
12353
12860
  const transformValue = computed(() => exec("getTransform"));
12861
+ const isConnection = computed(() => {
12862
+ return elementSelection.value.length === 1 && Boolean(elementSelection.value[0].connection?.isValid());
12863
+ });
12354
12864
  const movable = computed(() => {
12355
- return state.value !== "typing" && elementSelection.value.every((element) => {
12865
+ return state.value !== "typing" && !isConnection.value && elementSelection.value.every((element) => {
12356
12866
  return !isLock(element) && element.meta.movable !== false && element.meta.transformable !== false;
12357
12867
  });
12358
12868
  });
12359
12869
  const resizable = computed(() => {
12360
- return state.value !== "typing" && elementSelection.value.every((element) => {
12870
+ return state.value !== "typing" && !isConnection.value && elementSelection.value.every((element) => {
12361
12871
  return !isLock(element) && element.meta.resizable !== false && element.meta.transformable !== false;
12362
12872
  });
12363
12873
  });
12364
12874
  const rotatable = computed(() => {
12365
- return state.value !== "typing" && elementSelection.value.every((element) => {
12875
+ return state.value !== "typing" && !isConnection.value && elementSelection.value.every((element) => {
12366
12876
  return !isLock(element) && element.meta.rotatable !== false && element.meta.transformable !== false;
12367
12877
  });
12368
12878
  });
12369
12879
  const roundable = computed(() => {
12370
- if (state.value !== "typing" && elementSelection.value.length === 1) {
12880
+ if (state.value !== "typing" && !isConnection.value && elementSelection.value.length === 1) {
12371
12881
  const element = elementSelection.value[0];
12372
12882
  return hoverElement.value?.equal(element) && !isLock(element) && element.foreground.isValid();
12373
12883
  }
@@ -12379,7 +12889,7 @@ var Selection_default = /* @__PURE__ */ defineComponent({
12379
12889
  }
12380
12890
  __expose({ transform });
12381
12891
  return (_ctx, _cache) => {
12382
- return openBlock(), createElementBlock("div", _hoisted_1$14, [
12892
+ return openBlock(), createElementBlock("div", _hoisted_1$15, [
12383
12893
  (openBlock(true), createElementBlock(Fragment, null, renderList(parentObbStyles.value, (style, index) => {
12384
12894
  return openBlock(), createElementBlock("div", {
12385
12895
  key: index,
@@ -12940,7 +13450,7 @@ var slice_default = definePlugin((editor) => {
12940
13450
  });
12941
13451
  //#endregion
12942
13452
  //#region src/components/SmartGuides.vue?vue&type=script&setup=true&lang.ts
12943
- var _hoisted_1$13 = {
13453
+ var _hoisted_1$14 = {
12944
13454
  key: 0,
12945
13455
  class: "m-smart-guides"
12946
13456
  };
@@ -12952,7 +13462,7 @@ var SmartGuides_default = /* @__PURE__ */ defineComponent({
12952
13462
  setup(__props) {
12953
13463
  const { state } = useEditor();
12954
13464
  return (_ctx, _cache) => {
12955
- return unref(state) === "transforming" || unref(state) === "moving" ? (openBlock(), createElementBlock("div", _hoisted_1$13, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.snapLines, (item, key) => {
13465
+ return unref(state) === "transforming" || unref(state) === "moving" ? (openBlock(), createElementBlock("div", _hoisted_1$14, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.snapLines, (item, key) => {
12956
13466
  return openBlock(), createElementBlock("div", {
12957
13467
  key,
12958
13468
  class: normalizeClass(item.class.map((v) => `m-smart-guides__${v}`)),
@@ -13917,7 +14427,7 @@ var smartGuides_default = definePlugin((editor) => {
13917
14427
  if (box) {
13918
14428
  const excluded = new Set(elementSelection.value.map((el) => el.instanceId));
13919
14429
  const { vLines, hLines } = parent.value.children.filter((node) => {
13920
- return !excluded.has(node.instanceId) && isElement(node) && viewportAabb.value.overlap(node.globalAabb);
14430
+ return !excluded.has(node.instanceId) && isElement(node) && !node.connection?.isValid() && viewportAabb.value.overlap(node.globalAabb);
13921
14431
  }).map((node) => createBox(node)).filter(Boolean).reduce((store, box) => {
13922
14432
  [
13923
14433
  box.vt,
@@ -14176,7 +14686,7 @@ function isLeftTopLine(line) {
14176
14686
  }
14177
14687
  //#endregion
14178
14688
  //#region src/components/SmartSelection.vue?vue&type=script&setup=true&lang.ts
14179
- var _hoisted_1$12 = ["onPointerdown"];
14689
+ var _hoisted_1$13 = ["onPointerdown"];
14180
14690
  //#endregion
14181
14691
  //#region src/components/SmartSelection.vue
14182
14692
  var SmartSelection_default = /* @__PURE__ */ defineComponent({
@@ -14585,7 +15095,7 @@ var SmartSelection_default = /* @__PURE__ */ defineComponent({
14585
15095
  }, [createElementVNode("div", {
14586
15096
  class: "m-smart-selection__ring",
14587
15097
  onPointerdown: ($event) => onRingDrag($event, item)
14588
- }, null, 40, _hoisted_1$12)], 6);
15098
+ }, null, 40, _hoisted_1$13)], 6);
14589
15099
  }), 128)), currentTransform.value.width && currentTransform.value.height ? (openBlock(), createBlock(Transform_default, mergeProps({
14590
15100
  key: 0,
14591
15101
  "model-value": currentTransform.value
@@ -14667,13 +15177,13 @@ var state_default = definePlugin((editor) => {
14667
15177
  });
14668
15178
  //#endregion
14669
15179
  //#region src/components/shared/ProgressIndicator.vue?vue&type=script&setup=true&lang.ts
14670
- var _hoisted_1$11 = { class: "m-progress-indicator" };
14671
- var _hoisted_2$6 = {
15180
+ var _hoisted_1$12 = { class: "m-progress-indicator" };
15181
+ var _hoisted_2$7 = {
14672
15182
  key: 0,
14673
15183
  class: "m-progress-indicator__status"
14674
15184
  };
14675
- var _hoisted_3$6 = { class: "m-progress-indicator__bar" };
14676
- var _hoisted_4$3 = {
15185
+ var _hoisted_3$7 = { class: "m-progress-indicator__bar" };
15186
+ var _hoisted_4$4 = {
14677
15187
  key: 1,
14678
15188
  class: "m-progress-indicator__bar-indeterminate"
14679
15189
  };
@@ -14692,22 +15202,22 @@ var ProgressIndicator_default = /* @__PURE__ */ _plugin_vue_export_helper_defaul
14692
15202
  setup(__props) {
14693
15203
  const progress = useModel(__props, "modelValue");
14694
15204
  return (_ctx, _cache) => {
14695
- return openBlock(), createElementBlock("div", _hoisted_1$11, [__props.label ? (openBlock(), createElementBlock("span", _hoisted_2$6, toDisplayString(__props.label), 1)) : createCommentVNode("", true), createElementVNode("div", _hoisted_3$6, [!__props.indeterminate ? (openBlock(), createElementBlock("div", {
15205
+ return openBlock(), createElementBlock("div", _hoisted_1$12, [__props.label ? (openBlock(), createElementBlock("span", _hoisted_2$7, toDisplayString(__props.label), 1)) : createCommentVNode("", true), createElementVNode("div", _hoisted_3$7, [!__props.indeterminate ? (openBlock(), createElementBlock("div", {
14696
15206
  key: 0,
14697
15207
  class: "m-progress-indicator__bar-fill",
14698
15208
  style: normalizeStyle({ width: `${progress.value * 100}%` })
14699
- }, null, 4)) : (openBlock(), createElementBlock("div", _hoisted_4$3))])]);
15209
+ }, null, 4)) : (openBlock(), createElementBlock("div", _hoisted_4$4))])]);
14700
15210
  };
14701
15211
  }
14702
15212
  }), [["__scopeId", "data-v-cc8ac0cb"]]);
14703
15213
  //#endregion
14704
15214
  //#region src/components/Statusbar.vue?vue&type=script&setup=true&lang.ts
14705
- var _hoisted_1$10 = { class: "m-statusbar" };
14706
- var _hoisted_2$5 = { class: "m-statusbar__main" };
14707
- var _hoisted_3$5 = { class: "m-statusbar__item" };
14708
- var _hoisted_4$2 = { class: "m-statusbar__kbd" };
14709
- var _hoisted_5$1 = { class: "m-statusbar__kbd" };
14710
- var _hoisted_6$1 = { class: "m-statusbar__item" };
15215
+ var _hoisted_1$11 = { class: "m-statusbar" };
15216
+ var _hoisted_2$6 = { class: "m-statusbar__main" };
15217
+ var _hoisted_3$6 = { class: "m-statusbar__item" };
15218
+ var _hoisted_4$3 = { class: "m-statusbar__kbd" };
15219
+ var _hoisted_5$2 = { class: "m-statusbar__kbd" };
15220
+ var _hoisted_6$2 = { class: "m-statusbar__item" };
14711
15221
  var _hoisted_7$1 = { class: "m-statusbar__kbd" };
14712
15222
  var _hoisted_8$1 = { class: "m-statusbar__item" };
14713
15223
  var _hoisted_9$1 = { class: "m-statusbar__item" };
@@ -14731,10 +15241,10 @@ var Statusbar_default = /* @__PURE__ */ _plugin_vue_export_helper_default(/* @__
14731
15241
  setup(__props) {
14732
15242
  const { state, t, getKbd, exporting, exportProgress, selection, isElement } = useEditor();
14733
15243
  return (_ctx, _cache) => {
14734
- return openBlock(), createElementBlock("div", _hoisted_1$10, [createElementVNode("div", _hoisted_2$5, [unref(state) === "typing" ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
14735
- createElementVNode("div", _hoisted_3$5, [createElementVNode("span", _hoisted_4$2, toDisplayString(unref(getKbd)("Command")), 1), createElementVNode("span", _hoisted_5$1, toDisplayString(unref(getKbd)("Enter")), 1)]),
15244
+ return openBlock(), createElementBlock("div", _hoisted_1$11, [createElementVNode("div", _hoisted_2$6, [unref(state) === "typing" ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
15245
+ createElementVNode("div", _hoisted_3$6, [createElementVNode("span", _hoisted_4$3, toDisplayString(unref(getKbd)("Command")), 1), createElementVNode("span", _hoisted_5$2, toDisplayString(unref(getKbd)("Enter")), 1)]),
14736
15246
  _cache[1] || (_cache[1] = createElementVNode("span", null, "/", -1)),
14737
- createElementVNode("div", _hoisted_6$1, [createElementVNode("span", _hoisted_7$1, toDisplayString(unref(getKbd)("Escape")), 1), createElementVNode("span", null, toDisplayString(unref(t)("commitChanges")), 1)])
15247
+ createElementVNode("div", _hoisted_6$2, [createElementVNode("span", _hoisted_7$1, toDisplayString(unref(getKbd)("Escape")), 1), createElementVNode("span", null, toDisplayString(unref(t)("commitChanges")), 1)])
14738
15248
  ], 64)) : unref(state) === "transforming" || unref(state) === "moving" ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [
14739
15249
  createElementVNode("div", _hoisted_8$1, [createVNode(unref(Icon_default), { icon: "$mouseRightClick" })]),
14740
15250
  _cache[3] || (_cache[3] = createElementVNode("span", null, "\xA0/\xA0", -1)),
@@ -14811,29 +15321,29 @@ var test_default = definePlugin((editor) => {
14811
15321
  });
14812
15322
  //#endregion
14813
15323
  //#region src/components/timeline/Playhead.vue?vue&type=script&setup=true&lang.ts
14814
- var _hoisted_1$9 = { class: "m-payhead" };
15324
+ var _hoisted_1$10 = { class: "m-payhead" };
14815
15325
  //#endregion
14816
15326
  //#region src/components/timeline/Playhead.vue
14817
15327
  var Playhead_default = /* @__PURE__ */ defineComponent({
14818
15328
  __name: "Playhead",
14819
15329
  setup(__props) {
14820
15330
  return (_ctx, _cache) => {
14821
- return openBlock(), createElementBlock("div", _hoisted_1$9, [..._cache[0] || (_cache[0] = [createElementVNode("header", { class: "m-payhead__header" }, null, -1), createElementVNode("main", { class: "m-payhead__main" }, null, -1)])]);
15331
+ return openBlock(), createElementBlock("div", _hoisted_1$10, [..._cache[0] || (_cache[0] = [createElementVNode("header", { class: "m-payhead__header" }, null, -1), createElementVNode("main", { class: "m-payhead__main" }, null, -1)])]);
14822
15332
  };
14823
15333
  }
14824
15334
  });
14825
15335
  //#endregion
14826
15336
  //#region src/components/timeline/Segment.vue?vue&type=script&setup=true&lang.ts
14827
- var _hoisted_1$8 = ["onMousedown"];
14828
- var _hoisted_2$4 = {
15337
+ var _hoisted_1$9 = ["onMousedown"];
15338
+ var _hoisted_2$5 = {
14829
15339
  key: 0,
14830
15340
  class: "m-segment__edge m-segment__edge--front"
14831
15341
  };
14832
- var _hoisted_3$4 = {
15342
+ var _hoisted_3$5 = {
14833
15343
  class: "m-segment__node",
14834
15344
  style: { "overflow": "hidden" }
14835
15345
  };
14836
- var _hoisted_4$1 = {
15346
+ var _hoisted_4$2 = {
14837
15347
  key: 1,
14838
15348
  class: "m-segment__edge m-segment__edge--end"
14839
15349
  };
@@ -14998,33 +15508,33 @@ var Segment_default = /* @__PURE__ */ defineComponent({
14998
15508
  class: normalizeClass(["m-segment__block", `m-segment__block--${block.kind}`]),
14999
15509
  style: normalizeStyle(blockStyle(block)),
15000
15510
  onMousedown: ($event) => onBlockDown($event, block)
15001
- }, null, 46, _hoisted_1$8);
15511
+ }, null, 46, _hoisted_1$9);
15002
15512
  }), 128)),
15003
- __props.active ? (openBlock(), createElementBlock("div", _hoisted_2$4)) : createCommentVNode("", true),
15004
- createElementVNode("span", _hoisted_3$4, toDisplayString(unref(thumbnailName)), 1),
15005
- __props.active ? (openBlock(), createElementBlock("div", _hoisted_4$1)) : createCommentVNode("", true)
15513
+ __props.active ? (openBlock(), createElementBlock("div", _hoisted_2$5)) : createCommentVNode("", true),
15514
+ createElementVNode("span", _hoisted_3$5, toDisplayString(unref(thumbnailName)), 1),
15515
+ __props.active ? (openBlock(), createElementBlock("div", _hoisted_4$2)) : createCommentVNode("", true)
15006
15516
  ], 38);
15007
15517
  };
15008
15518
  }
15009
15519
  });
15010
15520
  //#endregion
15011
15521
  //#region src/components/timeline/Track.vue?vue&type=script&setup=true&lang.ts
15012
- var _hoisted_1$7 = { class: "m-track" };
15522
+ var _hoisted_1$8 = { class: "m-track" };
15013
15523
  //#endregion
15014
15524
  //#region src/components/timeline/Track.vue
15015
15525
  var Track_default = /* @__PURE__ */ defineComponent({
15016
15526
  __name: "Track",
15017
15527
  setup(__props) {
15018
15528
  return (_ctx, _cache) => {
15019
- return openBlock(), createElementBlock("div", _hoisted_1$7, [renderSlot(_ctx.$slots, "default")]);
15529
+ return openBlock(), createElementBlock("div", _hoisted_1$8, [renderSlot(_ctx.$slots, "default")]);
15020
15530
  };
15021
15531
  }
15022
15532
  });
15023
15533
  //#endregion
15024
15534
  //#region src/components/timeline/Trackhead.vue?vue&type=script&setup=true&lang.ts
15025
- var _hoisted_1$6 = ["data-id"];
15026
- var _hoisted_2$3 = { class: "m-trackhead__thumbnail" };
15027
- var _hoisted_3$3 = { key: 1 };
15535
+ var _hoisted_1$7 = ["data-id"];
15536
+ var _hoisted_2$4 = { class: "m-trackhead__thumbnail" };
15537
+ var _hoisted_3$4 = { key: 1 };
15028
15538
  //#endregion
15029
15539
  //#region src/components/timeline/Trackhead.vue
15030
15540
  var Trackhead_default = /* @__PURE__ */ defineComponent({
@@ -15115,7 +15625,7 @@ var Trackhead_default = /* @__PURE__ */ defineComponent({
15115
15625
  onMouseenter,
15116
15626
  onMouseleave
15117
15627
  }, [
15118
- createElementVNode("div", _hoisted_2$3, [createVNode(unref(Icon_default), { icon: unref(thumbnailIcon) }, null, 8, ["icon"])]),
15628
+ createElementVNode("div", _hoisted_2$4, [createVNode(unref(Icon_default), { icon: unref(thumbnailIcon) }, null, 8, ["icon"])]),
15119
15629
  createElementVNode("div", {
15120
15630
  class: "m-trackhead__name",
15121
15631
  onDblclick: onDblclickName
@@ -15132,7 +15642,7 @@ var Trackhead_default = /* @__PURE__ */ defineComponent({
15132
15642
  onBlur: onInputBlur,
15133
15643
  onKeydown: onInputKeydown,
15134
15644
  onMousedown: _cache[1] || (_cache[1] = withModifiers(() => {}, ["stop"]))
15135
- }, null, 544)), [[vModelText, editValue.value]]) : (openBlock(), createElementBlock("span", _hoisted_3$3, toDisplayString(unref(thumbnailName)), 1))], 32),
15645
+ }, null, 544)), [[vModelText, editValue.value]]) : (openBlock(), createElementBlock("span", _hoisted_3$4, toDisplayString(unref(thumbnailName)), 1))], 32),
15136
15646
  createElementVNode("div", { class: normalizeClass(["m-trackhead__action", { "m-trackhead__action--show": showActions.value }]) }, [createElementVNode("button", {
15137
15647
  type: "button",
15138
15648
  class: normalizeClass(["m-trackhead__btn", { "m-trackhead__btn--show": unref(isLock)(__props.node) }]),
@@ -15144,18 +15654,18 @@ var Trackhead_default = /* @__PURE__ */ defineComponent({
15144
15654
  onMousedown: _cache[3] || (_cache[3] = withModifiers(() => {}, ["stop"])),
15145
15655
  onClick: onToggleVisible
15146
15656
  }, [createVNode(unref(Icon_default), { icon: unref(isVisible)(__props.node) ? "$visible" : "$unvisible" }, null, 8, ["icon"])], 34)], 2)
15147
- ], 42, _hoisted_1$6);
15657
+ ], 42, _hoisted_1$7);
15148
15658
  };
15149
15659
  }
15150
15660
  });
15151
15661
  //#endregion
15152
15662
  //#region src/components/timeline/Timeline.vue?vue&type=script&setup=true&lang.ts
15153
- var _hoisted_1$5 = { class: "m-timeline__toolbar" };
15154
- var _hoisted_2$2 = { class: "m-timeline__time" };
15155
- var _hoisted_3$2 = { class: "m-timeline__time--muted" };
15156
- var _hoisted_4 = { class: "m-timeline__controls" };
15157
- var _hoisted_5 = ["title"];
15158
- var _hoisted_6 = ["title"];
15663
+ var _hoisted_1$6 = { class: "m-timeline__toolbar" };
15664
+ var _hoisted_2$3 = { class: "m-timeline__time" };
15665
+ var _hoisted_3$3 = { class: "m-timeline__time--muted" };
15666
+ var _hoisted_4$1 = { class: "m-timeline__controls" };
15667
+ var _hoisted_5$1 = ["title"];
15668
+ var _hoisted_6$1 = ["title"];
15159
15669
  var _hoisted_7 = ["title"];
15160
15670
  var _hoisted_8 = ["title"];
15161
15671
  var _hoisted_9 = ["title"];
@@ -15253,25 +15763,25 @@ var Timeline_default = /* @__PURE__ */ defineComponent({
15253
15763
  return openBlock(), createElementBlock("div", {
15254
15764
  class: "m-timeline",
15255
15765
  onWheel: _cache[6] || (_cache[6] = withModifiers(() => {}, ["prevent"]))
15256
- }, [createElementVNode("div", _hoisted_1$5, [
15257
- createElementVNode("div", _hoisted_2$2, [
15766
+ }, [createElementVNode("div", _hoisted_1$6, [
15767
+ createElementVNode("div", _hoisted_2$3, [
15258
15768
  createElementVNode("span", null, toDisplayString(currentLabel.value), 1),
15259
15769
  _cache[7] || (_cache[7] = createElementVNode("span", { class: "m-timeline__time-sep" }, "/", -1)),
15260
- createElementVNode("span", _hoisted_3$2, toDisplayString(totalLabel.value), 1)
15770
+ createElementVNode("span", _hoisted_3$3, toDisplayString(totalLabel.value), 1)
15261
15771
  ]),
15262
- createElementVNode("div", _hoisted_4, [
15772
+ createElementVNode("div", _hoisted_4$1, [
15263
15773
  createElementVNode("button", {
15264
15774
  class: "m-timeline__btn",
15265
15775
  type: "button",
15266
15776
  title: unref(t)("seekStart"),
15267
15777
  onClick: _cache[0] || (_cache[0] = ($event) => unref(exec)("seekStart"))
15268
- }, [createVNode(unref(Icon_default), { icon: "$skipPrevious" })], 8, _hoisted_5),
15778
+ }, [createVNode(unref(Icon_default), { icon: "$skipPrevious" })], 8, _hoisted_5$1),
15269
15779
  createElementVNode("button", {
15270
15780
  class: "m-timeline__btn",
15271
15781
  type: "button",
15272
15782
  title: unref(t)("stepBackward"),
15273
15783
  onClick: _cache[1] || (_cache[1] = ($event) => unref(exec)("stepBackward"))
15274
- }, [createVNode(unref(Icon_default), { icon: "$stepBackward" })], 8, _hoisted_6),
15784
+ }, [createVNode(unref(Icon_default), { icon: "$stepBackward" })], 8, _hoisted_6$1),
15275
15785
  createElementVNode("button", {
15276
15786
  class: "m-timeline__btn m-timeline__btn--primary",
15277
15787
  type: "button",
@@ -15511,7 +16021,7 @@ var timeline_default = definePlugin((editor) => {
15511
16021
  });
15512
16022
  //#endregion
15513
16023
  //#region src/components/Drawing.vue?vue&type=script&setup=true&lang.ts
15514
- var _hoisted_1$4 = {
16024
+ var _hoisted_1$5 = {
15515
16025
  key: 0,
15516
16026
  class: "m-drawing__tip"
15517
16027
  };
@@ -15529,7 +16039,7 @@ var Drawing_default = /* @__PURE__ */ defineComponent({
15529
16039
  left: `${unref(drawboardPointer).x}px`,
15530
16040
  top: `${unref(drawboardPointer).y}px`
15531
16041
  })
15532
- }, [unref(activeTool)?.name ? (openBlock(), createElementBlock("div", _hoisted_1$4, toDisplayString(unref(t)(unref(activeTool).name)), 1)) : createCommentVNode("", true)], 4)) : createCommentVNode("", true);
16042
+ }, [unref(activeTool)?.name ? (openBlock(), createElementBlock("div", _hoisted_1$5, toDisplayString(unref(t)(unref(activeTool).name)), 1)) : createCommentVNode("", true)], 4)) : createCommentVNode("", true);
15533
16043
  };
15534
16044
  }
15535
16045
  });
@@ -15552,9 +16062,9 @@ var tool_default = definePlugin((editor) => {
15552
16062
  });
15553
16063
  //#endregion
15554
16064
  //#region src/components/Toolbelt.vue?vue&type=script&setup=true&lang.ts
15555
- var _hoisted_1$3 = { class: "m-toolbelt" };
15556
- var _hoisted_2$1 = { key: 0 };
15557
- var _hoisted_3$1 = { key: 1 };
16065
+ var _hoisted_1$4 = { class: "m-toolbelt" };
16066
+ var _hoisted_2$2 = { key: 0 };
16067
+ var _hoisted_3$2 = { key: 1 };
15558
16068
  //#endregion
15559
16069
  //#region src/components/Toolbelt.vue
15560
16070
  var Toolbelt_default = /* @__PURE__ */ defineComponent({
@@ -15642,7 +16152,7 @@ var Toolbelt_default = /* @__PURE__ */ defineComponent({
15642
16152
  ];
15643
16153
  });
15644
16154
  return (_ctx, _cache) => {
15645
- return openBlock(), createElementBlock("div", _hoisted_1$3, [(openBlock(true), createElementBlock(Fragment, null, renderList(items.value, (tool, key) => {
16155
+ return openBlock(), createElementBlock("div", _hoisted_1$4, [(openBlock(true), createElementBlock(Fragment, null, renderList(items.value, (tool, key) => {
15646
16156
  return openBlock(), createElementBlock("div", {
15647
16157
  key,
15648
16158
  class: "m-toolbelt__group"
@@ -15660,7 +16170,7 @@ var Toolbelt_default = /* @__PURE__ */ defineComponent({
15660
16170
  _: 2
15661
16171
  }, 1040, ["active", "onClick"])]),
15662
16172
  default: withCtx(() => [createElementVNode("span", null, toDisplayString(unref(t)(tool.key)), 1)]),
15663
- kbd: withCtx(() => [unref(hotkeys).has(`setState:${tool.key}`) ? (openBlock(), createElementBlock("span", _hoisted_2$1, toDisplayString(unref(getKbd)(`setState:${tool.key}`)), 1)) : unref(hotkeys).has(`activateTool:${tool.key}`) ? (openBlock(), createElementBlock("span", _hoisted_3$1, toDisplayString(unref(getKbd)(`activateTool:${tool.key}`)), 1)) : createCommentVNode("", true)]),
16173
+ kbd: withCtx(() => [unref(hotkeys).has(`setState:${tool.key}`) ? (openBlock(), createElementBlock("span", _hoisted_2$2, toDisplayString(unref(getKbd)(`setState:${tool.key}`)), 1)) : unref(hotkeys).has(`activateTool:${tool.key}`) ? (openBlock(), createElementBlock("span", _hoisted_3$2, toDisplayString(unref(getKbd)(`activateTool:${tool.key}`)), 1)) : createCommentVNode("", true)]),
15664
16174
  _: 2
15665
16175
  }, 1024), tool.children?.length ? (openBlock(), createBlock(Menu_default, {
15666
16176
  key: 0,
@@ -16078,6 +16588,9 @@ var TextEditor_default = /* @__PURE__ */ defineComponent({
16078
16588
  await nextTick();
16079
16589
  if (editor.pointerDown(e)) {
16080
16590
  editor.selectAll();
16591
+ requestAnimationFrame(() => {
16592
+ if (state.value === "typing") editor.selectAll();
16593
+ });
16081
16594
  return true;
16082
16595
  }
16083
16596
  return false;
@@ -16113,12 +16626,12 @@ var TextEditor_default = /* @__PURE__ */ defineComponent({
16113
16626
  }
16114
16627
  });
16115
16628
  //#endregion
16116
- //#region \0@oxc-project+runtime@0.130.0/helpers/decorateMetadata.js
16629
+ //#region \0@oxc-project+runtime@0.132.0/helpers/decorateMetadata.js
16117
16630
  function __decorateMetadata(k, v) {
16118
16631
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
16119
16632
  }
16120
16633
  //#endregion
16121
- //#region \0@oxc-project+runtime@0.130.0/helpers/decorate.js
16634
+ //#region \0@oxc-project+runtime@0.132.0/helpers/decorate.js
16122
16635
  function __decorate(decorators, target, key, desc) {
16123
16636
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
16124
16637
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -16428,8 +16941,10 @@ var TextEditor = class extends HTMLElement {
16428
16941
  let prevOldStyle = {};
16429
16942
  diffChars(oldString, newString).forEach((change) => {
16430
16943
  const chars = Array.from(change.value);
16431
- if (change.removed) oldStyleIndex += chars.length;
16432
- else chars.forEach(() => {
16944
+ if (change.removed) {
16945
+ prevOldStyle = normalizeStyle$1(oldStyles[oldStyleIndex] ?? {});
16946
+ oldStyleIndex += chars.length;
16947
+ } else chars.forEach(() => {
16433
16948
  if (change.added) styles[styleIndex] = { ...prevOldStyle };
16434
16949
  else {
16435
16950
  prevOldStyle = normalizeStyle$1(oldStyles[oldStyleIndex]);
@@ -16778,504 +17293,841 @@ __decorate([property({
16778
17293
  fallback: false
16779
17294
  }), __decorateMetadata("design:type", Boolean)], TextEditor.prototype, "_showCursor", void 0);
16780
17295
  //#endregion
16781
- //#region src/plugins/index.ts
16782
- var plugins = [
16783
- arrange_default,
16784
- autoNest_default,
16785
- clipboard_default,
16786
- doc_default,
16787
- edit_default,
16788
- formatPaint_default,
16789
- frame_default,
16790
- history_default,
16791
- hover_default,
16792
- html_default,
16793
- image_default,
16794
- import_default,
16795
- json_default,
16796
- layers_default,
16797
- madeWith_default,
16798
- memory_default,
16799
- menu_default,
16800
- node_default,
16801
- pen_default,
16802
- ruler_default,
16803
- saveAs_default,
16804
- scroll_default,
16805
- selection_default,
16806
- shape_default,
16807
- slice_default,
16808
- smartGuides_default,
16809
- smartSelection_default,
16810
- state_default,
16811
- statusbar_default,
16812
- test_default,
16813
- timeline_default,
16814
- tool_default,
16815
- toolbelt_default,
16816
- transform_default,
16817
- definePlugin((editor) => {
16818
- const { isElement, elementSelection, textSelection, fonts, registerConfig, t, addElement, activateTool } = editor;
16819
- const config = registerConfig("typography", { default: { strategy: "autoHeight" } });
16820
- const hasTextSelectionRange = computed(() => {
16821
- return (textSelection.value?.length ?? 0) > 1 && textSelection.value[0] !== textSelection.value[1];
16822
- });
16823
- const isTextAllSelected = computed(() => {
16824
- return textSelection.value?.[0].isFirst && textSelection.value?.[1].isLast && textSelection.value?.[1].isLastSelected;
16825
- });
16826
- function textFontSizeToFit(element, scale) {
16827
- function _handle(element) {
16828
- if (!scale) {
16829
- const chars = element.text.base.characters;
16830
- let pos = 0;
16831
- let char;
16832
- chars.forEach((_char) => {
16833
- const _pos = _char.lineBox.left + _char.lineBox.width;
16834
- if (_pos > pos) {
16835
- char = _char;
16836
- pos = _pos;
16837
- }
16838
- });
16839
- const style = {};
16840
- const content = chars.filter((_char) => _char.lineBox.top === char?.lineBox.top).map((char) => {
16841
- Object.assign(style, { ...char.parent.style }, { ...char.parent.parent.style });
16842
- return char.content;
16843
- }).join("");
16844
- const { boundingBox } = measureText({
16845
- fonts,
16846
- style: {
16847
- ...element.style.toJSON(),
16848
- width: "auto"
16849
- },
16850
- content: [{ fragments: [{
16851
- ...style,
16852
- content
16853
- }] }]
16854
- });
16855
- const fontSize = (element.style.fontSize || 12) / 2;
16856
- scale = (element.style.width ?? 0) / (boundingBox.width + fontSize);
16857
- }
16858
- function _scaleStyle(style) {
16859
- if (style.fontSize) style.fontSize = style.fontSize * scale;
16860
- if (style.letterSpacing) style.letterSpacing = style.letterSpacing * scale;
16861
- }
16862
- _scaleStyle(element.style);
16863
- if (element.text?.isValid?.() && Array.isArray(element.text?.content)) element.text.content.forEach((p) => {
16864
- _scaleStyle(p);
16865
- p.fragments.forEach((f) => {
16866
- _scaleStyle(f);
16867
- });
17296
+ //#region src/plugins/typography.ts
17297
+ var typography_default = definePlugin((editor) => {
17298
+ const { isElement, elementSelection, textSelection, fonts, registerConfig, t, addElement, activateTool } = editor;
17299
+ const config = registerConfig("typography", { default: { strategy: "autoHeight" } });
17300
+ const hasTextSelectionRange = computed(() => {
17301
+ return (textSelection.value?.length ?? 0) > 1 && textSelection.value[0] !== textSelection.value[1];
17302
+ });
17303
+ const isTextAllSelected = computed(() => {
17304
+ return textSelection.value?.[0].isFirst && textSelection.value?.[1].isLast && textSelection.value?.[1].isLastSelected;
17305
+ });
17306
+ function textFontSizeToFit(element, scale) {
17307
+ function _handle(element) {
17308
+ if (!scale) {
17309
+ const chars = element.text.base.characters;
17310
+ let pos = 0;
17311
+ let char;
17312
+ chars.forEach((_char) => {
17313
+ const _pos = _char.lineBox.left + _char.lineBox.width;
17314
+ if (_pos > pos) {
17315
+ char = _char;
17316
+ pos = _pos;
17317
+ }
16868
17318
  });
16869
- element.requestRender();
16870
- }
16871
- _handle(element);
16872
- element.findOne((descendant) => {
16873
- if (isElement(descendant)) _handle(descendant);
16874
- return false;
16875
- });
16876
- }
16877
- function textToFit(element, strategy = config.value.strategy) {
16878
- if (strategy === "fixedWidthHeight") return;
16879
- else if (strategy === "autoFontSize") {
16880
- textFontSizeToFit(element);
16881
- return;
16882
- }
16883
- function _handle(element) {
16884
- if (!element.text?.isValid?.() || typeof element.text?.content !== "object") return;
16885
- const isVertical = element.text.base.isVertical;
16886
- const style = element.style.toJSON();
16887
- switch (strategy) {
16888
- case "autoWidth":
16889
- if (isVertical) style.height = "auto";
16890
- else style.width = "auto";
16891
- break;
16892
- case "autoHeight":
16893
- if (isVertical) style.width = "auto";
16894
- else style.height = "auto";
16895
- break;
16896
- }
17319
+ const style = {};
17320
+ const content = chars.filter((_char) => _char.lineBox.top === char?.lineBox.top).map((char) => {
17321
+ Object.assign(style, { ...char.parent.style }, { ...char.parent.parent.style });
17322
+ return char.content;
17323
+ }).join("");
16897
17324
  const { boundingBox } = measureText({
16898
17325
  fonts,
16899
- style,
16900
- content: element.text.content
17326
+ style: {
17327
+ ...element.style.toJSON(),
17328
+ width: "auto"
17329
+ },
17330
+ content: [{ fragments: [{
17331
+ ...style,
17332
+ content
17333
+ }] }]
16901
17334
  });
16902
- if (element.style.width !== boundingBox.width || element.style.height !== boundingBox.height) {
16903
- element.style.width = boundingBox.width;
16904
- element.style.height = boundingBox.height;
16905
- element.requestRender();
16906
- }
17335
+ const fontSize = (element.style.fontSize || 12) / 2;
17336
+ scale = (element.style.width ?? 0) / (boundingBox.width + fontSize);
16907
17337
  }
16908
- _handle(element);
16909
- element.findOne((descendant) => {
16910
- if (isElement(descendant)) _handle(descendant);
16911
- return false;
16912
- });
16913
- }
16914
- function handleTextSelection([start, end], cb) {
16915
- let flag = true;
16916
- elementSelection.value[0]?.text?.content.forEach((p, pIndex, pItems) => {
16917
- if (!flag) return;
16918
- p.fragments.forEach((f, fIndex, fItems) => {
16919
- if (!flag) return;
16920
- const { content, ...fStyle } = f;
16921
- Array.from(normalizeCRLF(content)).forEach((c, cIndex, cItems) => {
16922
- flag = cb({
16923
- selected: (pIndex > start.paragraphIndex || pIndex === start.paragraphIndex && fIndex > start.fragmentIndex || pIndex === start.paragraphIndex && fIndex === start.fragmentIndex && cIndex >= start.charIndex) && (pIndex < end.paragraphIndex || pIndex === end.paragraphIndex && fIndex < end.fragmentIndex || pIndex === end.paragraphIndex && fIndex === end.fragmentIndex && (end.isLastSelected ? cIndex <= end.charIndex : cIndex < end.charIndex)),
16924
- p,
16925
- pIndex,
16926
- pLength: pItems.length,
16927
- f,
16928
- fIndex,
16929
- fStyle,
16930
- fLength: fItems.length,
16931
- c,
16932
- cLength: cItems.length,
16933
- cIndex
16934
- });
16935
- });
17338
+ function _scaleStyle(style) {
17339
+ if (style.fontSize) style.fontSize = style.fontSize * scale;
17340
+ if (style.letterSpacing) style.letterSpacing = style.letterSpacing * scale;
17341
+ }
17342
+ _scaleStyle(element.style);
17343
+ if (element.text?.isValid?.() && Array.isArray(element.text?.content)) element.text.content.forEach((p) => {
17344
+ _scaleStyle(p);
17345
+ p.fragments.forEach((f) => {
17346
+ _scaleStyle(f);
16936
17347
  });
16937
17348
  });
17349
+ element.requestRender();
16938
17350
  }
16939
- function getTextStyle(key) {
16940
- const el = elementSelection.value[0];
16941
- if (!el) return;
16942
- let value;
16943
- switch (key) {
16944
- case "fill":
16945
- case "outline":
16946
- value = el.text[key];
17351
+ _handle(element);
17352
+ element.findOne((descendant) => {
17353
+ if (isElement(descendant)) _handle(descendant);
17354
+ return false;
17355
+ });
17356
+ }
17357
+ function textToFit(element, strategy = config.value.strategy) {
17358
+ if (strategy === "fixedWidthHeight") return;
17359
+ else if (strategy === "autoFontSize") {
17360
+ textFontSizeToFit(element);
17361
+ return;
17362
+ }
17363
+ function _handle(element) {
17364
+ if (!element.text?.isValid?.() || typeof element.text?.content !== "object") return;
17365
+ const isVertical = element.text.base.isVertical;
17366
+ const style = element.style.toJSON();
17367
+ switch (strategy) {
17368
+ case "autoWidth":
17369
+ if (isVertical) style.height = "auto";
17370
+ else style.width = "auto";
16947
17371
  break;
16948
- default:
16949
- value = el.style[key];
17372
+ case "autoHeight":
17373
+ if (isVertical) style.width = "auto";
17374
+ else style.height = "auto";
16950
17375
  break;
16951
17376
  }
16952
- if (hasTextSelectionRange.value && !isTextAllSelected.value) {
16953
- const selection = textSelection.value;
16954
- if (selection && selection[0] && selection[1]) handleTextSelection(selection, ({ selected, fStyle }) => {
16955
- if (selected && fStyle[key]) {
16956
- value = fStyle[key];
16957
- return false;
16958
- }
16959
- return true;
17377
+ const { boundingBox } = measureText({
17378
+ fonts,
17379
+ style,
17380
+ content: element.text.content
17381
+ });
17382
+ if (element.style.width !== boundingBox.width || element.style.height !== boundingBox.height) {
17383
+ element.style.width = boundingBox.width;
17384
+ element.style.height = boundingBox.height;
17385
+ element.requestRender();
17386
+ }
17387
+ }
17388
+ _handle(element);
17389
+ element.findOne((descendant) => {
17390
+ if (isElement(descendant)) _handle(descendant);
17391
+ return false;
17392
+ });
17393
+ }
17394
+ function handleTextSelection([start, end], cb) {
17395
+ let flag = true;
17396
+ elementSelection.value[0]?.text?.content.forEach((p, pIndex, pItems) => {
17397
+ if (!flag) return;
17398
+ p.fragments.forEach((f, fIndex, fItems) => {
17399
+ if (!flag) return;
17400
+ const { content, ...fStyle } = f;
17401
+ Array.from(normalizeCRLF(content)).forEach((c, cIndex, cItems) => {
17402
+ flag = cb({
17403
+ selected: (pIndex > start.paragraphIndex || pIndex === start.paragraphIndex && fIndex > start.fragmentIndex || pIndex === start.paragraphIndex && fIndex === start.fragmentIndex && cIndex >= start.charIndex) && (pIndex < end.paragraphIndex || pIndex === end.paragraphIndex && fIndex < end.fragmentIndex || pIndex === end.paragraphIndex && fIndex === end.fragmentIndex && (end.isLastSelected ? cIndex <= end.charIndex : cIndex < end.charIndex)),
17404
+ p,
17405
+ pIndex,
17406
+ pLength: pItems.length,
17407
+ f,
17408
+ fIndex,
17409
+ fStyle,
17410
+ fLength: fItems.length,
17411
+ c,
17412
+ cLength: cItems.length,
17413
+ cIndex
17414
+ });
16960
17415
  });
16961
- } else {
16962
- const content = el.text.content;
16963
- switch (key) {
16964
- case "fontSize": return content?.reduce((prev, p) => {
16965
- return p.fragments.reduce((prev, f) => {
16966
- return ~~Math.max(prev, f[key] ?? 0);
16967
- }, prev);
16968
- }, value) ?? value;
16969
- default: if (content?.length === 1 && content[0].fragments.length === 1 && content[0].fragments[0][key]) return content[0].fragments[0][key];
17416
+ });
17417
+ });
17418
+ }
17419
+ function getTextStyle(key) {
17420
+ const el = elementSelection.value[0];
17421
+ if (!el) return;
17422
+ let value;
17423
+ switch (key) {
17424
+ case "fill":
17425
+ case "outline":
17426
+ value = el.text[key];
17427
+ break;
17428
+ default:
17429
+ value = el.style[key];
17430
+ break;
17431
+ }
17432
+ if (hasTextSelectionRange.value && !isTextAllSelected.value) {
17433
+ const selection = textSelection.value;
17434
+ if (selection && selection[0] && selection[1]) handleTextSelection(selection, ({ selected, fStyle }) => {
17435
+ if (selected && fStyle[key]) {
17436
+ value = fStyle[key];
17437
+ return false;
16970
17438
  }
17439
+ return true;
17440
+ });
17441
+ } else {
17442
+ const content = el.text.content;
17443
+ switch (key) {
17444
+ case "fontSize": return content?.reduce((prev, p) => {
17445
+ return p.fragments.reduce((prev, f) => {
17446
+ return ~~Math.max(prev, f[key] ?? 0);
17447
+ }, prev);
17448
+ }, value) ?? value;
17449
+ default: if (content?.length === 1 && content[0].fragments.length === 1 && content[0].fragments[0][key]) return content[0].fragments[0][key];
16971
17450
  }
16972
- return value;
16973
17451
  }
16974
- function setTextContentByEachFragment(handler) {
16975
- const el = elementSelection.value[0];
16976
- if (!el) return;
16977
- const newContent = [];
16978
- let newParagraph = { fragments: [] };
16979
- let newFragment;
16980
- handleTextSelection(textSelection.value, ({ selected, fIndex, fStyle, fLength, c, cIndex, cLength }) => {
16981
- if (fIndex === 0 && cIndex === 0) {
17452
+ return value;
17453
+ }
17454
+ function setTextContentByEachFragment(handler) {
17455
+ const el = elementSelection.value[0];
17456
+ if (!el) return;
17457
+ const newContent = [];
17458
+ let newParagraph = { fragments: [] };
17459
+ let newFragment;
17460
+ handleTextSelection(textSelection.value, ({ selected, fIndex, fStyle, fLength, c, cIndex, cLength }) => {
17461
+ if (fIndex === 0 && cIndex === 0) {
17462
+ newParagraph = { fragments: [] };
17463
+ newFragment = void 0;
17464
+ }
17465
+ const style = { ...fStyle };
17466
+ if (selected) handler(style);
17467
+ if (newFragment) {
17468
+ const { content: _, ..._style } = newFragment;
17469
+ if (isEqualObject(style, _style)) newFragment.content += c;
17470
+ else {
17471
+ newParagraph.fragments.push(newFragment);
17472
+ newFragment = {
17473
+ ...style,
17474
+ content: c
17475
+ };
17476
+ }
17477
+ } else newFragment = {
17478
+ ...style,
17479
+ content: c
17480
+ };
17481
+ if (fIndex === fLength - 1 && cIndex === cLength - 1) {
17482
+ if (newFragment) newParagraph.fragments.push(newFragment);
17483
+ if (newParagraph.fragments.length) {
17484
+ newContent.push(newParagraph);
16982
17485
  newParagraph = { fragments: [] };
16983
- newFragment = void 0;
16984
17486
  }
16985
- const style = { ...fStyle };
16986
- if (selected) handler(style);
16987
- if (newFragment) {
16988
- const { content: _, ..._style } = newFragment;
16989
- if (isEqualObject(style, _style)) newFragment.content += c;
16990
- else {
16991
- newParagraph.fragments.push(newFragment);
16992
- newFragment = {
16993
- ...style,
16994
- content: c
16995
- };
16996
- }
16997
- } else newFragment = {
16998
- ...style,
16999
- content: c
17000
- };
17001
- if (fIndex === fLength - 1 && cIndex === cLength - 1) {
17002
- if (newFragment) newParagraph.fragments.push(newFragment);
17003
- if (newParagraph.fragments.length) {
17004
- newContent.push(newParagraph);
17005
- newParagraph = { fragments: [] };
17487
+ }
17488
+ return true;
17489
+ });
17490
+ if (newContent.length) el.text = {
17491
+ ...el.text.toJSON(),
17492
+ content: newContent
17493
+ };
17494
+ }
17495
+ function setTextStyle(key, value) {
17496
+ const el = elementSelection.value[0];
17497
+ if (!el) return;
17498
+ switch (key) {
17499
+ case "writingMode":
17500
+ if (el.style[key] !== value) {
17501
+ const { width, height } = el.style;
17502
+ el.style.width = height;
17503
+ el.style.height = width;
17504
+ el.style[key] = value;
17505
+ }
17506
+ break;
17507
+ default:
17508
+ if (hasTextSelectionRange.value && !isTextAllSelected.value) setTextContentByEachFragment((fragment) => {
17509
+ fragment[key] = value;
17510
+ });
17511
+ else {
17512
+ switch (key) {
17513
+ case "fill":
17514
+ case "outline":
17515
+ el.text[key] = value;
17516
+ break;
17517
+ default:
17518
+ el.style[key] = value;
17519
+ break;
17006
17520
  }
17521
+ el.text.content.forEach((p) => {
17522
+ delete p[key];
17523
+ p.fragments.forEach((f) => {
17524
+ delete f[key];
17525
+ });
17526
+ });
17527
+ el.text = el.text.toJSON();
17007
17528
  }
17008
- return true;
17529
+ el.requestDraw();
17530
+ textToFit(el);
17531
+ break;
17532
+ }
17533
+ }
17534
+ function getTextFill() {
17535
+ const el = elementSelection.value[0];
17536
+ if (!el) return;
17537
+ let fill;
17538
+ if (hasTextSelectionRange.value) {
17539
+ fill = getTextStyle("fill");
17540
+ if (!fill) fill = { color: getTextStyle("color") };
17541
+ }
17542
+ fill = fill ?? el.text.fill ?? { color: el.style.color };
17543
+ return fill;
17544
+ }
17545
+ function setTextFill(value) {
17546
+ const el = elementSelection.value[0];
17547
+ if (!el) return;
17548
+ if (hasTextSelectionRange.value && value?.color) setTextStyle("fill", value);
17549
+ else {
17550
+ el.text.fill = value;
17551
+ if (value?.color) el.style.color = value.color;
17552
+ el.text.content.forEach((p) => {
17553
+ delete p.fill;
17554
+ delete p.color;
17555
+ p.fragments.forEach((f) => {
17556
+ delete f.fill;
17557
+ delete f.color;
17558
+ });
17009
17559
  });
17010
- if (newContent.length) el.text = {
17560
+ el.text = {
17011
17561
  ...el.text.toJSON(),
17012
- content: newContent
17562
+ fill: value
17013
17563
  };
17564
+ el.requestDraw();
17014
17565
  }
17015
- function setTextStyle(key, value) {
17016
- const el = elementSelection.value[0];
17017
- if (!el) return;
17018
- switch (key) {
17019
- case "writingMode":
17020
- if (el.style[key] !== value) {
17021
- const { width, height } = el.style;
17022
- el.style.width = height;
17023
- el.style.height = width;
17024
- el.style[key] = value;
17025
- }
17026
- break;
17027
- default:
17028
- if (hasTextSelectionRange.value && !isTextAllSelected.value) setTextContentByEachFragment((fragment) => {
17029
- fragment[key] = value;
17030
- });
17031
- else {
17032
- switch (key) {
17033
- case "fill":
17034
- case "outline":
17035
- el.text[key] = value;
17036
- break;
17037
- default:
17038
- el.style[key] = value;
17039
- break;
17040
- }
17041
- el.text.content.forEach((p) => {
17042
- delete p[key];
17043
- p.fragments.forEach((f) => {
17044
- delete f[key];
17045
- });
17046
- });
17047
- el.text = el.text.toJSON();
17048
- }
17049
- el.requestDraw();
17050
- textToFit(el);
17051
- break;
17566
+ }
17567
+ const addTextElement = (options = {}) => {
17568
+ const { content = t("doubleClickEditText"), style, ...restOptions } = options;
17569
+ return addElement(createTextElement(content, {
17570
+ fontSize: 64,
17571
+ ...style
17572
+ }), {
17573
+ sizeToFit: true,
17574
+ active: true,
17575
+ ...restOptions
17576
+ });
17577
+ };
17578
+ Object.assign(editor, {
17579
+ hasTextSelectionRange,
17580
+ isTextAllSelected
17581
+ });
17582
+ return {
17583
+ name: "mce:typography",
17584
+ commands: [
17585
+ {
17586
+ command: "addTextElement",
17587
+ handle: addTextElement
17588
+ },
17589
+ {
17590
+ command: "handleTextSelection",
17591
+ handle: handleTextSelection
17592
+ },
17593
+ {
17594
+ command: "textFontSizeToFit",
17595
+ handle: textFontSizeToFit
17596
+ },
17597
+ {
17598
+ command: "textToFit",
17599
+ handle: textToFit
17600
+ },
17601
+ {
17602
+ command: "setTextStyle",
17603
+ handle: setTextStyle
17604
+ },
17605
+ {
17606
+ command: "getTextStyle",
17607
+ handle: getTextStyle
17608
+ },
17609
+ {
17610
+ command: "getTextFill",
17611
+ handle: getTextFill
17612
+ },
17613
+ {
17614
+ command: "setTextFill",
17615
+ handle: setTextFill
17616
+ },
17617
+ {
17618
+ command: "setTextContentByEachFragment",
17619
+ handle: setTextContentByEachFragment
17052
17620
  }
17621
+ ],
17622
+ hotkeys: [{
17623
+ command: "activateTool:text",
17624
+ key: "T"
17625
+ }],
17626
+ loaders: [{
17627
+ name: "txt",
17628
+ accept: ".txt",
17629
+ test: (source) => {
17630
+ if (source instanceof Blob) {
17631
+ if (source.type.startsWith("text/plain")) return true;
17632
+ }
17633
+ if (source instanceof File) {
17634
+ if (/\.txt$/i.test(source.name)) return true;
17635
+ }
17636
+ return false;
17637
+ },
17638
+ load: async (source) => {
17639
+ return createTextElement(await source.text());
17640
+ }
17641
+ }],
17642
+ tools: [{
17643
+ name: "text",
17644
+ handle: (position) => {
17645
+ addTextElement({ position });
17646
+ activateTool(void 0);
17647
+ }
17648
+ }],
17649
+ components: [{
17650
+ type: "overlay",
17651
+ component: TextEditor_default
17652
+ }],
17653
+ setup: async () => {
17654
+ const { setDefaultFont } = editor;
17655
+ onBeforeMount(() => {
17656
+ TextEditor.register();
17657
+ });
17658
+ const defaultFont = config.value.defaultFont;
17659
+ if (defaultFont) await setDefaultFont(defaultFont);
17053
17660
  }
17054
- function getTextFill() {
17055
- const el = elementSelection.value[0];
17056
- if (!el) return;
17057
- let fill;
17058
- if (hasTextSelectionRange.value) {
17059
- fill = getTextStyle("fill");
17060
- if (!fill) fill = { color: getTextStyle("color") };
17661
+ };
17662
+ });
17663
+ //#endregion
17664
+ //#region src/plugins/url.ts
17665
+ var url_default = definePlugin((editor) => {
17666
+ const { load, http } = editor;
17667
+ return {
17668
+ name: "mce:url",
17669
+ loaders: [{
17670
+ name: "url",
17671
+ test: (source) => {
17672
+ return typeof source === "string";
17673
+ },
17674
+ load: async (url) => {
17675
+ const blob = await http.request({
17676
+ url,
17677
+ responseType: "blob"
17678
+ });
17679
+ const file = new File([blob], url, { type: blob.type });
17680
+ try {
17681
+ return await load(file);
17682
+ } catch (error) {
17683
+ throw new Error(`Failed to load source "${url}", ${error}`);
17684
+ }
17061
17685
  }
17062
- fill = fill ?? el.text.fill ?? { color: el.style.color };
17063
- return fill;
17686
+ }]
17687
+ };
17688
+ });
17689
+ //#endregion
17690
+ //#region src/plugins/view.ts
17691
+ var view_default = definePlugin((editor) => {
17692
+ const { config, components } = editor;
17693
+ const getUiConfig = (name) => {
17694
+ return config.value.ui[name];
17695
+ };
17696
+ const setUiVisible = (name, visible) => {
17697
+ const obj = getUiConfig(name);
17698
+ if (obj && "visible" in obj) if (visible === "toggle") obj.visible = !obj.visible;
17699
+ else obj.visible = visible;
17700
+ };
17701
+ const isPanelVisible = (name) => {
17702
+ return Boolean(components.value.find((c) => c.type === "panel" && c.name === name)?.visible.value);
17703
+ };
17704
+ const setPanelVisible = (name, visible) => {
17705
+ const c = components.value.find((c) => c.type === "panel" && c.name === name);
17706
+ if (c) if (visible === "toggle") c.visible.value = !c.visible.value;
17707
+ else c.visible.value = visible;
17708
+ };
17709
+ return {
17710
+ name: "mce:view",
17711
+ commands: [
17712
+ {
17713
+ command: "getUiConfig",
17714
+ handle: getUiConfig
17715
+ },
17716
+ {
17717
+ command: "isUiVisible",
17718
+ handle: (name) => Boolean(getUiConfig(name)?.visible)
17719
+ },
17720
+ {
17721
+ command: "setUiVisible",
17722
+ handle: setUiVisible
17723
+ },
17724
+ {
17725
+ command: "hideUi",
17726
+ handle: (name) => setUiVisible(name, false)
17727
+ },
17728
+ {
17729
+ command: "showUi",
17730
+ handle: (name) => setUiVisible(name, true)
17731
+ },
17732
+ {
17733
+ command: "toggleUi",
17734
+ handle: (name) => setUiVisible(name, "toggle")
17735
+ },
17736
+ {
17737
+ command: "isPanelVisible",
17738
+ handle: isPanelVisible
17739
+ },
17740
+ {
17741
+ command: "setPanelVisible",
17742
+ handle: setPanelVisible
17743
+ },
17744
+ {
17745
+ command: "hidePanel",
17746
+ handle: (name) => setPanelVisible(name, false)
17747
+ },
17748
+ {
17749
+ command: "showPanel",
17750
+ handle: (name) => setPanelVisible(name, true)
17751
+ },
17752
+ {
17753
+ command: "togglePanel",
17754
+ handle: (name) => setPanelVisible(name, "toggle")
17755
+ }
17756
+ ],
17757
+ hotkeys: [{
17758
+ command: "toggleUi:pixelGrid",
17759
+ key: "Shift+\""
17760
+ }, {
17761
+ command: "toggleUi:ruler",
17762
+ key: "Shift+R"
17763
+ }]
17764
+ };
17765
+ });
17766
+ //#endregion
17767
+ //#region src/utils/workflow.ts
17768
+ var INPUT_PORT = {
17769
+ idx: 0,
17770
+ x: 0,
17771
+ y: .5,
17772
+ ang: Math.PI,
17773
+ kind: "input"
17774
+ };
17775
+ var OUTPUT_PORT = {
17776
+ idx: 1,
17777
+ x: 1,
17778
+ y: .5,
17779
+ ang: 0,
17780
+ kind: "output"
17781
+ };
17782
+ function getWorkflowPorts(el) {
17783
+ if (el.meta?.inEditorIs === "Frame") return [OUTPUT_PORT];
17784
+ return [INPUT_PORT, OUTPUT_PORT];
17785
+ }
17786
+ function toConnectionPoints(ports) {
17787
+ return ports.map(({ idx, x, y, ang }) => ({
17788
+ idx,
17789
+ x,
17790
+ y,
17791
+ ang
17792
+ }));
17793
+ }
17794
+ //#endregion
17795
+ //#region src/components/Workflow.vue?vue&type=script&setup=true&lang.ts
17796
+ var _hoisted_1$3 = {
17797
+ key: 0,
17798
+ class: "m-workflow"
17799
+ };
17800
+ var _hoisted_2$1 = {
17801
+ key: 0,
17802
+ class: "m-workflow__preview"
17803
+ };
17804
+ var _hoisted_3$1 = ["d"];
17805
+ var _hoisted_4 = ["onPointerdown"];
17806
+ var _hoisted_5 = ["onClick"];
17807
+ var _hoisted_6 = { class: "m-workflow__menu-kbd" };
17808
+ var PORT_GAP = 16;
17809
+ //#endregion
17810
+ //#region src/components/Workflow.vue
17811
+ var Workflow_default = /* @__PURE__ */ defineComponent({
17812
+ __name: "Workflow",
17813
+ setup(__props) {
17814
+ const { mode, elementSelection, getAabb, camera, drawboardAabb, root, isElement, exec } = useEditor();
17815
+ const NODE_TYPES = [
17816
+ {
17817
+ type: "text",
17818
+ label: "文字生成",
17819
+ kbd: "⇧T"
17820
+ },
17821
+ {
17822
+ type: "image",
17823
+ label: "图片生成",
17824
+ kbd: "⇧I"
17825
+ },
17826
+ {
17827
+ type: "video",
17828
+ label: "视频生成",
17829
+ kbd: "⇧V"
17830
+ }
17831
+ ];
17832
+ function isConnectable(el) {
17833
+ return isElement(el) && !el.connection?.isValid?.();
17064
17834
  }
17065
- function setTextFill(value) {
17835
+ const selectedNode = computed(() => {
17836
+ if (mode.value !== "workflow") return void 0;
17066
17837
  const el = elementSelection.value[0];
17067
- if (!el) return;
17068
- if (hasTextSelectionRange.value && value?.color) setTextStyle("fill", value);
17069
- else {
17070
- el.text.fill = value;
17071
- if (value?.color) el.style.color = value.color;
17072
- el.text.content.forEach((p) => {
17073
- delete p.fill;
17074
- delete p.color;
17075
- p.fragments.forEach((f) => {
17076
- delete f.fill;
17077
- delete f.color;
17078
- });
17079
- });
17080
- el.text = {
17081
- ...el.text.toJSON(),
17082
- fill: value
17838
+ return el && isConnectable(el) ? el : void 0;
17839
+ });
17840
+ const ports = computed(() => {
17841
+ const el = selectedNode.value;
17842
+ if (!el) return [];
17843
+ const a = getAabb(el, "drawboard");
17844
+ return getWorkflowPorts(el).map((p) => {
17845
+ let dx = p.x - .5;
17846
+ let dy = p.y - .5;
17847
+ const len = Math.hypot(dx, dy) || 1;
17848
+ dx /= len;
17849
+ dy /= len;
17850
+ return {
17851
+ kind: p.kind,
17852
+ idx: p.idx,
17853
+ x: a.left + a.width * p.x + dx * PORT_GAP,
17854
+ y: a.top + a.height * p.y + dy * PORT_GAP
17083
17855
  };
17084
- el.requestDraw();
17085
- }
17856
+ });
17857
+ });
17858
+ const drag = ref();
17859
+ const menu = ref();
17860
+ function toDrawboard(e) {
17861
+ return {
17862
+ x: e.clientX - drawboardAabb.value.left,
17863
+ y: e.clientY - drawboardAabb.value.top
17864
+ };
17086
17865
  }
17087
- const addTextElement = (options = {}) => {
17088
- const { content = t("doubleClickEditText"), style, ...restOptions } = options;
17089
- return addElement(createTextElement(content, {
17090
- fontSize: 64,
17091
- ...style
17092
- }), {
17093
- sizeToFit: true,
17094
- active: true,
17095
- ...restOptions
17866
+ function findNodeAt(point, excludeId) {
17867
+ return (root.value?.children ?? []).find((n) => {
17868
+ return isConnectable(n) && n.id !== excludeId && getAabb(n, "drawboard").contains(point);
17096
17869
  });
17097
- };
17098
- Object.assign(editor, {
17099
- hasTextSelectionRange,
17100
- isTextAllSelected
17870
+ }
17871
+ function connect(port, sourceId, otherId, otherPorts) {
17872
+ const need = port.kind === "output" ? "input" : "output";
17873
+ const other = otherPorts.find((p) => p.kind === need);
17874
+ if (!other) return false;
17875
+ if (port.kind === "output") exec("addWorkflowConnection", sourceId, port.idx, otherId, other.idx);
17876
+ else exec("addWorkflowConnection", otherId, other.idx, sourceId, port.idx);
17877
+ return true;
17878
+ }
17879
+ function startConnection(port, e) {
17880
+ e.stopPropagation();
17881
+ e.preventDefault();
17882
+ const el = selectedNode.value;
17883
+ if (!el) return;
17884
+ const sourceId = el.id;
17885
+ const from = {
17886
+ x: port.x,
17887
+ y: port.y
17888
+ };
17889
+ drag.value = {
17890
+ port,
17891
+ from,
17892
+ to: { ...from },
17893
+ sourceId
17894
+ };
17895
+ const onMove = (ev) => {
17896
+ if (drag.value) drag.value = {
17897
+ ...drag.value,
17898
+ to: toDrawboard(ev)
17899
+ };
17900
+ };
17901
+ const onUp = (ev) => {
17902
+ document.removeEventListener("pointermove", onMove);
17903
+ document.removeEventListener("pointerup", onUp);
17904
+ const drop = toDrawboard(ev);
17905
+ drag.value = void 0;
17906
+ const target = findNodeAt(drop, sourceId);
17907
+ if (target) connect(port, sourceId, target.id, getWorkflowPorts(target));
17908
+ else menu.value = {
17909
+ port,
17910
+ x: drop.x,
17911
+ y: drop.y,
17912
+ position: camera.value.toGlobal(drop, {
17913
+ x: 0,
17914
+ y: 0
17915
+ }),
17916
+ sourceId
17917
+ };
17918
+ };
17919
+ document.addEventListener("pointermove", onMove);
17920
+ document.addEventListener("pointerup", onUp);
17921
+ }
17922
+ function chooseNodeType(type) {
17923
+ const m = menu.value;
17924
+ menu.value = void 0;
17925
+ if (!m) return;
17926
+ const node = exec("addWorkflowNode", type);
17927
+ const w = node.style.width;
17928
+ const h = node.style.height;
17929
+ node.style.left = m.port.kind === "output" ? m.position.x : m.position.x - w;
17930
+ node.style.top = m.position.y - h / 2;
17931
+ connect(m.port, m.sourceId, node.id, [INPUT_PORT, OUTPUT_PORT]);
17932
+ }
17933
+ function closeMenu() {
17934
+ menu.value = void 0;
17935
+ }
17936
+ const previewPath = computed(() => {
17937
+ const d = drag.value;
17938
+ if (!d) return "";
17939
+ const { from, to } = d;
17940
+ const dx = Math.max(40, Math.abs(to.x - from.x) * .5);
17941
+ return `M ${from.x} ${from.y} C ${from.x + dx} ${from.y} ${to.x - dx} ${to.y} ${to.x} ${to.y}`;
17101
17942
  });
17102
- return {
17103
- name: "mce:typography",
17104
- commands: [
17105
- {
17106
- command: "addTextElement",
17107
- handle: addTextElement
17108
- },
17109
- {
17110
- command: "handleTextSelection",
17111
- handle: handleTextSelection
17112
- },
17113
- {
17114
- command: "textFontSizeToFit",
17115
- handle: textFontSizeToFit
17116
- },
17117
- {
17118
- command: "textToFit",
17119
- handle: textToFit
17120
- },
17121
- {
17122
- command: "setTextStyle",
17123
- handle: setTextStyle
17124
- },
17125
- {
17126
- command: "getTextStyle",
17127
- handle: getTextStyle
17128
- },
17129
- {
17130
- command: "getTextFill",
17131
- handle: getTextFill
17943
+ function portStyle(p) {
17944
+ return {
17945
+ left: `${p.x}px`,
17946
+ top: `${p.y}px`
17947
+ };
17948
+ }
17949
+ return (_ctx, _cache) => {
17950
+ return unref(mode) === "workflow" ? (openBlock(), createElementBlock("div", _hoisted_1$3, [
17951
+ drag.value ? (openBlock(), createElementBlock("svg", _hoisted_2$1, [createElementVNode("path", { d: previewPath.value }, null, 8, _hoisted_3$1)])) : createCommentVNode("", true),
17952
+ (openBlock(true), createElementBlock(Fragment, null, renderList(ports.value, (port) => {
17953
+ return openBlock(), createElementBlock("div", {
17954
+ key: `${port.kind}:${port.idx}`,
17955
+ class: "m-workflow__port",
17956
+ style: normalizeStyle(portStyle(port)),
17957
+ onPointerdown: ($event) => startConnection(port, $event)
17958
+ }, [createVNode(unref(Icon_default), { icon: "$plus" })], 44, _hoisted_4);
17959
+ }), 128)),
17960
+ menu.value ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [createElementVNode("div", {
17961
+ class: "m-workflow__backdrop",
17962
+ onPointerdown: closeMenu
17963
+ }, null, 32), createElementVNode("div", {
17964
+ class: "m-workflow__menu",
17965
+ style: normalizeStyle({
17966
+ left: `${menu.value.x}px`,
17967
+ top: `${menu.value.y}px`
17968
+ })
17969
+ }, [_cache[0] || (_cache[0] = createElementVNode("div", { class: "m-workflow__menu-title" }, " 新增节点 ", -1)), (openBlock(), createElementBlock(Fragment, null, renderList(NODE_TYPES, (n) => {
17970
+ return createElementVNode("button", {
17971
+ key: n.type,
17972
+ type: "button",
17973
+ class: "m-workflow__menu-item",
17974
+ onClick: ($event) => chooseNodeType(n.type)
17975
+ }, [createElementVNode("span", null, toDisplayString(n.label), 1), createElementVNode("span", _hoisted_6, toDisplayString(n.kbd), 1)], 8, _hoisted_5);
17976
+ }), 64))], 4)], 64)) : createCommentVNode("", true)
17977
+ ])) : createCommentVNode("", true);
17978
+ };
17979
+ }
17980
+ });
17981
+ //#endregion
17982
+ //#region src/plugins/workflow.ts
17983
+ var DEFAULT_NODES = {
17984
+ text: {
17985
+ label: "文字生成",
17986
+ title: "✍️ 双击此处输入文字..",
17987
+ body: ["可以在此输入提示词,比如画面描述、产品卖点、活动主题、场景描述、品牌 slogan 等内容。若暂时没有明确内容,也可先输入关键词或草稿,后续随时修改优化哦!", "也可以在底部输入框输入需求,让 AI 自动完成文字生成。"]
17988
+ },
17989
+ image: {
17990
+ label: "图片生成",
17991
+ title: "🖼️ 双击此处描述画面..",
17992
+ body: ["输入画面描述、风格、主体等内容,让 AI 自动完成图片生成。"]
17993
+ },
17994
+ video: {
17995
+ label: "视频生成",
17996
+ title: "🎬 双击此处描述视频..",
17997
+ body: ["输入分镜、动作、风格等内容,让 AI 自动完成视频生成。"]
17998
+ }
17999
+ };
18000
+ var RECT_PATH = "M0 0h24v24H0z";
18001
+ //#endregion
18002
+ //#region src/plugins/index.ts
18003
+ var plugins = [
18004
+ arrange_default,
18005
+ autoNest_default,
18006
+ clipboard_default,
18007
+ doc_default,
18008
+ edit_default,
18009
+ formatPaint_default,
18010
+ frame_default,
18011
+ history_default,
18012
+ hover_default,
18013
+ html_default,
18014
+ image_default,
18015
+ import_default,
18016
+ json_default,
18017
+ layers_default,
18018
+ madeWith_default,
18019
+ memory_default,
18020
+ menu_default,
18021
+ node_default,
18022
+ pen_default,
18023
+ ruler_default,
18024
+ saveAs_default,
18025
+ scroll_default,
18026
+ selection_default,
18027
+ shape_default,
18028
+ slice_default,
18029
+ smartGuides_default,
18030
+ smartSelection_default,
18031
+ state_default,
18032
+ statusbar_default,
18033
+ test_default,
18034
+ timeline_default,
18035
+ tool_default,
18036
+ toolbelt_default,
18037
+ transform_default,
18038
+ typography_default,
18039
+ url_default,
18040
+ view_default,
18041
+ definePlugin((editor, options) => {
18042
+ const { addElement, renderEngine } = editor;
18043
+ function getTemplate(type) {
18044
+ return {
18045
+ ...DEFAULT_NODES[type],
18046
+ ...options.workflowNodes?.[type]
18047
+ };
18048
+ }
18049
+ function buildContent(t) {
18050
+ return [...t.title ? [{ fragments: [{
18051
+ content: t.title,
18052
+ color: "#1f2937",
18053
+ fontWeight: 700
18054
+ }] }] : [], ...(t.body ?? []).map((line) => ({ fragments: [{
18055
+ content: line,
18056
+ color: "#9ca3af"
18057
+ }] }))];
18058
+ }
18059
+ function createWorkflowNode(type) {
18060
+ const t = getTemplate(type);
18061
+ return {
18062
+ name: t.label ?? type,
18063
+ style: {
18064
+ width: 380,
18065
+ height: 280,
18066
+ borderRadius: 20,
18067
+ padding: 28,
18068
+ fontSize: 16,
18069
+ lineHeight: 1.6
17132
18070
  },
17133
- {
17134
- command: "setTextFill",
17135
- handle: setTextFill
18071
+ shape: [{ data: RECT_PATH }],
18072
+ fill: "#ffffff",
18073
+ outline: {
18074
+ color: "#ececf0",
18075
+ width: 1
17136
18076
  },
17137
- {
17138
- command: "setTextContentByEachFragment",
17139
- handle: setTextContentByEachFragment
18077
+ text: { content: buildContent(t) },
18078
+ meta: {
18079
+ inPptIs: "Shape",
18080
+ inCanvasIs: "Element2D"
17140
18081
  }
17141
- ],
17142
- hotkeys: [{
17143
- command: "activateTool:text",
17144
- key: "T"
17145
- }],
17146
- loaders: [{
17147
- name: "txt",
17148
- accept: ".txt",
17149
- test: (source) => {
17150
- if (source instanceof Blob) {
17151
- if (source.type.startsWith("text/plain")) return true;
17152
- }
17153
- if (source instanceof File) {
17154
- if (/\.txt$/i.test(source.name)) return true;
17155
- }
17156
- return false;
18082
+ };
18083
+ }
18084
+ function addWorkflowNode(type, position) {
18085
+ return addElement(createWorkflowNode(type), {
18086
+ position,
18087
+ active: true
18088
+ });
18089
+ }
18090
+ function materializePorts(id) {
18091
+ const el = renderEngine.value.nodeMap.get(id);
18092
+ if (el && !el.shape?.connectionPoints?.length) el.shape.connectionPoints = toConnectionPoints(getWorkflowPorts(el));
18093
+ }
18094
+ function addWorkflowConnection(startId, startIdx, endId, endIdx) {
18095
+ materializePorts(startId);
18096
+ materializePorts(endId);
18097
+ return addElement({
18098
+ style: { pointerEvents: "none" },
18099
+ outline: {
18100
+ color: "#94a3b8",
18101
+ width: 2,
18102
+ lineCap: "round",
18103
+ lineJoin: "round"
17157
18104
  },
17158
- load: async (source) => {
17159
- return createTextElement(await source.text());
17160
- }
17161
- }],
17162
- tools: [{
17163
- name: "text",
17164
- handle: (position) => {
17165
- addTextElement({ position });
17166
- activateTool(void 0);
17167
- }
17168
- }],
17169
- components: [{
17170
- type: "overlay",
17171
- component: TextEditor_default
17172
- }],
17173
- setup: async () => {
17174
- const { setDefaultFont } = editor;
17175
- onBeforeMount(() => {
17176
- TextEditor.register();
17177
- });
17178
- const defaultFont = config.value.defaultFont;
17179
- if (defaultFont) await setDefaultFont(defaultFont);
17180
- }
17181
- };
17182
- }),
17183
- definePlugin((editor) => {
17184
- const { load, http } = editor;
17185
- return {
17186
- name: "mce:url",
17187
- loaders: [{
17188
- name: "url",
17189
- test: (source) => {
17190
- return typeof source === "string";
18105
+ connection: {
18106
+ start: {
18107
+ id: startId,
18108
+ idx: startIdx
18109
+ },
18110
+ end: {
18111
+ id: endId,
18112
+ idx: endIdx
18113
+ },
18114
+ mode: "curved"
17191
18115
  },
17192
- load: async (url) => {
17193
- const blob = await http.request({
17194
- url,
17195
- responseType: "blob"
17196
- });
17197
- const file = new File([blob], url, { type: blob.type });
17198
- try {
17199
- return await load(file);
17200
- } catch (error) {
17201
- throw new Error(`Failed to load source "${url}", ${error}`);
17202
- }
17203
- }
17204
- }]
17205
- };
17206
- }),
17207
- definePlugin((editor) => {
17208
- const { config, components } = editor;
17209
- const getUiConfig = (name) => {
17210
- return config.value.ui[name];
17211
- };
17212
- const setUiVisible = (name, visible) => {
17213
- const obj = getUiConfig(name);
17214
- if (obj && "visible" in obj) if (visible === "toggle") obj.visible = !obj.visible;
17215
- else obj.visible = visible;
17216
- };
17217
- const isPanelVisible = (name) => {
17218
- return Boolean(components.value.find((c) => c.type === "panel" && c.name === name)?.visible.value);
17219
- };
17220
- const setPanelVisible = (name, visible) => {
17221
- const c = components.value.find((c) => c.type === "panel" && c.name === name);
17222
- if (c) if (visible === "toggle") c.visible.value = !c.visible.value;
17223
- else c.visible.value = visible;
17224
- };
18116
+ meta: { inCanvasIs: "Element2D" }
18117
+ });
18118
+ }
17225
18119
  return {
17226
- name: "mce:view",
17227
- commands: [
17228
- {
17229
- command: "getUiConfig",
17230
- handle: getUiConfig
17231
- },
17232
- {
17233
- command: "isUiVisible",
17234
- handle: (name) => Boolean(getUiConfig(name)?.visible)
17235
- },
17236
- {
17237
- command: "setUiVisible",
17238
- handle: setUiVisible
17239
- },
17240
- {
17241
- command: "hideUi",
17242
- handle: (name) => setUiVisible(name, false)
17243
- },
17244
- {
17245
- command: "showUi",
17246
- handle: (name) => setUiVisible(name, true)
17247
- },
17248
- {
17249
- command: "toggleUi",
17250
- handle: (name) => setUiVisible(name, "toggle")
17251
- },
17252
- {
17253
- command: "isPanelVisible",
17254
- handle: isPanelVisible
17255
- },
17256
- {
17257
- command: "setPanelVisible",
17258
- handle: setPanelVisible
17259
- },
17260
- {
17261
- command: "hidePanel",
17262
- handle: (name) => setPanelVisible(name, false)
17263
- },
17264
- {
17265
- command: "showPanel",
17266
- handle: (name) => setPanelVisible(name, true)
17267
- },
17268
- {
17269
- command: "togglePanel",
17270
- handle: (name) => setPanelVisible(name, "toggle")
17271
- }
17272
- ],
17273
- hotkeys: [{
17274
- command: "toggleUi:pixelGrid",
17275
- key: "Shift+\""
18120
+ name: "mce:workflow",
18121
+ commands: [{
18122
+ command: "addWorkflowNode",
18123
+ handle: addWorkflowNode
17276
18124
  }, {
17277
- command: "toggleUi:ruler",
17278
- key: "Shift+R"
18125
+ command: "addWorkflowConnection",
18126
+ handle: addWorkflowConnection
18127
+ }],
18128
+ components: [{
18129
+ type: "overlay",
18130
+ component: Workflow_default
17279
18131
  }]
17280
18132
  };
17281
18133
  }),
@@ -17840,11 +18692,7 @@ var _hoisted_3 = {
17840
18692
  var EditorLayout_default = /* @__PURE__ */ defineComponent({
17841
18693
  __name: "EditorLayout",
17842
18694
  props: {
17843
- ...makeMceStrategyProps({
17844
- activeStrategy: defaultActiveStrategy,
17845
- doubleclickStrategy: defaultDoubleclickStrategy,
17846
- hoverStrategy: defaultHoverStrategy
17847
- }),
18695
+ ...makeMceStrategyProps(),
17848
18696
  editor: Editor
17849
18697
  },
17850
18698
  setup(__props) {
@@ -17858,6 +18706,9 @@ var EditorLayout_default = /* @__PURE__ */ defineComponent({
17858
18706
  editor.setup();
17859
18707
  provide(IconsSymbol, createIcons());
17860
18708
  const { sortedComponents, componentRefs, isElement, isFrameNode, drawboardDom, renderEngine, camera, hoverElement, state, setCursor, exec, isLock, t, selectionAabbInDrawboard, selectionMarquee, elementSelection, drawboardAabb, screenCenterOffset, activeTool } = editor;
18709
+ const activeStrategy = computed(() => props.activeStrategy ?? editor.activeStrategy);
18710
+ const doubleclickStrategy = computed(() => props.doubleclickStrategy ?? editor.doubleclickStrategy);
18711
+ const hoverStrategy = computed(() => props.hoverStrategy ?? editor.hoverStrategy);
17861
18712
  const overlayContainer = useTemplateRef("overlayContainerTpl");
17862
18713
  const canvas = useTemplateRef("canvasTpl");
17863
18714
  const grabbing = ref(false);
@@ -17910,7 +18761,7 @@ var EditorLayout_default = /* @__PURE__ */ defineComponent({
17910
18761
  })) cursor = "move";
17911
18762
  else {
17912
18763
  const element = event.target;
17913
- const result = props.hoverStrategy({
18764
+ const result = hoverStrategy.value({
17914
18765
  element,
17915
18766
  event,
17916
18767
  editor
@@ -17953,7 +18804,7 @@ var EditorLayout_default = /* @__PURE__ */ defineComponent({
17953
18804
  });
17954
18805
  if (button === 2) {
17955
18806
  if (!inSelection) {
17956
- const result = props.activeStrategy({
18807
+ const result = activeStrategy.value({
17957
18808
  element,
17958
18809
  event: downEvent,
17959
18810
  editor
@@ -17974,7 +18825,7 @@ var EditorLayout_default = /* @__PURE__ */ defineComponent({
17974
18825
  const _dy = Math.abs(currentPos.y - _lastClickPos.y);
17975
18826
  if (now - _lastClickTime < 300 && _dx < 5 && _dy < 5) {
17976
18827
  _lastClickTime = 0;
17977
- props.doubleclickStrategy({
18828
+ doubleclickStrategy.value({
17978
18829
  event: downEvent,
17979
18830
  editor
17980
18831
  });
@@ -17996,7 +18847,7 @@ var EditorLayout_default = /* @__PURE__ */ defineComponent({
17996
18847
  break;
17997
18848
  }
17998
18849
  function onDrag(event) {
17999
- const result = props.activeStrategy({
18850
+ const result = activeStrategy.value({
18000
18851
  element,
18001
18852
  event,
18002
18853
  editor
@@ -18017,7 +18868,7 @@ var EditorLayout_default = /* @__PURE__ */ defineComponent({
18017
18868
  selected = elementSelection.value;
18018
18869
  }
18019
18870
  function onActivate() {
18020
- const result = props.activeStrategy({
18871
+ const result = activeStrategy.value({
18021
18872
  element,
18022
18873
  event: downEvent,
18023
18874
  editor
@@ -18329,4 +19180,4 @@ var Dialog_default = /* @__PURE__ */ defineComponent({
18329
19180
  }
18330
19181
  });
18331
19182
  //#endregion
18332
- export { Cropper_default as Cropper, Dialog_default as Dialog, Doc, Editor, Layers_default as EditorLayers, EditorLayout_default as EditorLayout, LayoutItem_default as EditorLayoutItem, Toolbelt_default as EditorToolbelt, Menu_default as Menu, Ruler_default as Ruler, Scrollbar_default as Scrollbar, Transform_default as Transform, defineMixin, definePlugin, mixins, plugins, useEditor };
19183
+ export { Cropper_default as Cropper, Dialog_default as Dialog, Doc, Editor, Layers_default as EditorLayers, EditorLayout_default as EditorLayout, LayoutItem_default as EditorLayoutItem, Toolbelt_default as EditorToolbelt, Menu_default as Menu, Ruler_default as Ruler, Scrollbar_default as Scrollbar, Transform_default as Transform, createCardElement, createFlowNodeElement, createImageElement, createShapeElement, createStickyElement, createTextElement, defineMixin, definePlugin, mixins, plugins, useEditor };