mce 0.18.4 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 = "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,
@@ -162,8 +189,9 @@ function createShapeElement(shape, fill, outline) {
162
189
  }
163
190
  };
164
191
  }
165
- function createTextElement(content, style) {
192
+ function createTextElement(content, style, fonts) {
166
193
  const box = measureText({
194
+ fonts,
167
195
  style,
168
196
  content
169
197
  }).boundingBox;
@@ -191,6 +219,182 @@ async function createImageElement(image) {
191
219
  }
192
220
  };
193
221
  }
222
+ /**
223
+ * A rounded panel with a bold title and optional body, composed as child text
224
+ * elements (so each line keeps its own styling and can be edited in place).
225
+ */
226
+ function createCardElement(title, options = {}) {
227
+ const { body, width = 220, height = 130, fill = "#ffffff", outline = {
228
+ color: "#e5e7eb",
229
+ width: 1
230
+ }, borderRadius = 12, padding = 16, titleStyle, bodyStyle } = options;
231
+ const children = [{
232
+ style: {
233
+ left: padding,
234
+ top: padding,
235
+ width: width - padding * 2,
236
+ fontSize: 18,
237
+ fontWeight: 700,
238
+ color: "#111827",
239
+ ...titleStyle
240
+ },
241
+ text: { content: normalizeTextContent(title) },
242
+ meta: { inCanvasIs: "Element2D" }
243
+ }];
244
+ if (body) children.push({
245
+ style: {
246
+ left: padding,
247
+ top: padding + 32,
248
+ width: width - padding * 2,
249
+ fontSize: 14,
250
+ color: "#6b7280",
251
+ ...bodyStyle
252
+ },
253
+ text: { content: normalizeTextContent(body) },
254
+ meta: { inCanvasIs: "Element2D" }
255
+ });
256
+ return {
257
+ style: {
258
+ width,
259
+ height,
260
+ borderRadius,
261
+ overflow: "hidden"
262
+ },
263
+ shape: [{ data: RECT_PATH }],
264
+ fill,
265
+ outline,
266
+ children,
267
+ meta: {
268
+ inPptIs: "Shape",
269
+ inCanvasIs: "Element2D"
270
+ }
271
+ };
272
+ }
273
+ /**
274
+ * A labelled rounded box that exposes connection points, so connectors can
275
+ * attach and route to it. Pairs with the `connection` element.
276
+ */
277
+ function createFlowNodeElement(label = "", options = {}) {
278
+ const { width = 160, height = 72, fill = "#e0edff", outline = {
279
+ color: "#4f8cff",
280
+ width: 2
281
+ }, borderRadius = 8, textStyle, connectionPoints = FLOW_CONNECTION_POINTS } = options;
282
+ return {
283
+ style: {
284
+ width,
285
+ height,
286
+ borderRadius,
287
+ textAlign: "center",
288
+ verticalAlign: "middle",
289
+ color: "#1e3a8a",
290
+ ...textStyle
291
+ },
292
+ shape: {
293
+ enabled: true,
294
+ paths: [{ data: RECT_PATH }],
295
+ connectionPoints
296
+ },
297
+ fill,
298
+ outline,
299
+ text: { content: normalizeTextContent(label) },
300
+ meta: {
301
+ inPptIs: "Shape",
302
+ inCanvasIs: "Element2D"
303
+ }
304
+ };
305
+ }
306
+ /** A solid colored note with top-aligned text, e.g. for whiteboard annotations. */
307
+ function createStickyElement(content, options = {}) {
308
+ const { width = 160, height = 160, fill = "#fff3a0", color = "#3f3f46", fontSize = 16, padding = 14 } = options;
309
+ return {
310
+ style: {
311
+ width,
312
+ height,
313
+ padding,
314
+ color,
315
+ fontSize
316
+ },
317
+ shape: [{ data: RECT_PATH }],
318
+ fill,
319
+ text: { content: normalizeTextContent(content) },
320
+ meta: {
321
+ inPptIs: "Shape",
322
+ inCanvasIs: "Element2D"
323
+ }
324
+ };
325
+ }
326
+ /** A grid table backed by the native `table` element property; first row is a header. */
327
+ function createTableElement(rows = 3, cols = 3, options = {}) {
328
+ const { width = 360, height = 160 } = options;
329
+ const cells = [];
330
+ for (let r = 0; r < rows; r++) for (let c = 0; c < cols; c++) cells.push({
331
+ row: r,
332
+ col: c,
333
+ children: [{
334
+ style: {
335
+ fontSize: 13,
336
+ color: "#333333",
337
+ textAlign: "center",
338
+ verticalAlign: "middle",
339
+ fontWeight: r === 0 ? 700 : 400
340
+ },
341
+ text: { content: normalizeTextContent(r === 0 ? `列 ${c + 1}` : "") },
342
+ meta: { inCanvasIs: "Element2D" }
343
+ }]
344
+ });
345
+ return {
346
+ style: {
347
+ width,
348
+ height
349
+ },
350
+ table: {
351
+ columns: Array.from({ length: cols }, () => ({ width: width / cols })),
352
+ rows: Array.from({ length: rows }, () => ({ height: height / rows })),
353
+ cells
354
+ },
355
+ meta: {
356
+ inPptIs: "Shape",
357
+ inCanvasIs: "Element2D",
358
+ inEditorIs: "Table"
359
+ }
360
+ };
361
+ }
362
+ /** A chart backed by the native `chart` element property (column/line/pie/…). */
363
+ function createChartElement(type = "column", options = {}) {
364
+ const { width = 360, height = 240, categories = [
365
+ "一月",
366
+ "二月",
367
+ "三月",
368
+ "四月",
369
+ "五月"
370
+ ], series = [{
371
+ name: "系列 1",
372
+ values: [
373
+ 40,
374
+ 70,
375
+ 55,
376
+ 90,
377
+ 60
378
+ ]
379
+ }] } = options;
380
+ return {
381
+ style: {
382
+ width,
383
+ height
384
+ },
385
+ chart: {
386
+ type,
387
+ categories,
388
+ series,
389
+ legend: "bottom"
390
+ },
391
+ meta: {
392
+ inPptIs: "Shape",
393
+ inCanvasIs: "Element2D",
394
+ inEditorIs: "Chart"
395
+ }
396
+ };
397
+ }
194
398
  //#endregion
195
399
  //#region src/utils/dnd.ts
196
400
  function addDragListener(downEvent, options = {}) {
@@ -906,7 +1110,7 @@ function signedArea(data, start, end, dim) {
906
1110
  return sum;
907
1111
  }
908
1112
  //#endregion
909
- //#region ../../node_modules/.pnpm/modern-path2d@1.6.0/node_modules/modern-path2d/dist/index.mjs
1113
+ //#region ../../node_modules/.pnpm/modern-path2d@1.7.0/node_modules/modern-path2d/dist/index.mjs
910
1114
  function drawPoint(ctx, x, y, options = {}) {
911
1115
  const { radius = 1 } = options;
912
1116
  ctx.moveTo(x, y);
@@ -1012,7 +1216,7 @@ var Vector2 = class Vector2 {
1012
1216
  return this.set(this._x * x, this._y * y);
1013
1217
  }
1014
1218
  divide(x = 0, y = x) {
1015
- return this.set(this._x / x, this._y / y);
1219
+ return this.set(x === 0 ? this._x : this._x / x, y === 0 ? this._y : this._y / y);
1016
1220
  }
1017
1221
  cross(p) {
1018
1222
  return this._x * p.y - this._y * p.x;
@@ -1190,9 +1394,9 @@ function getIntersectionPoint(p1, p2, q1, q2) {
1190
1394
  const s = q2.clone().sub(q1);
1191
1395
  const q1p1 = q1.clone().sub(p1);
1192
1396
  const crossRS = r.cross(s);
1193
- if (crossRS === 0) return new Vector2((p1.x + q1.x) / 2, (p1.y + q1.y) / 2);
1397
+ if (crossRS === 0) return null;
1194
1398
  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);
1399
+ if (Math.abs(t) > 1) return null;
1196
1400
  return new Vector2(p1.x + t * r.x, p1.y + t * r.y);
1197
1401
  }
1198
1402
  var FUNCTIONS_RE = /([\w-]+)\((.+?)\)/g;
@@ -1398,7 +1602,7 @@ function recursive(points, x1, y1, x2, y2, x3, y3, distanceTolerance, level) {
1398
1602
  function cross(ax, ay, bx, by, cx, cy) {
1399
1603
  return (bx - ax) * (cy - ay) - (by - ay) * (cx - ax);
1400
1604
  }
1401
- function windingNumber(px, py, polygon) {
1605
+ function windingNumber$1(px, py, polygon) {
1402
1606
  const polygonLen = polygon.length;
1403
1607
  let wn = 0;
1404
1608
  for (let i = 0, j = polygonLen - 2; i < polygonLen; j = i, i += 2) {
@@ -1417,11 +1621,18 @@ function distance(p1, p2) {
1417
1621
  const dy = p2[1] - p1[1];
1418
1622
  return Math.sqrt(dx * dx + dy * dy);
1419
1623
  }
1624
+ function aabbIntersects(a, b) {
1625
+ return a.minX <= b.maxX && a.maxX >= b.minX && a.minY <= b.maxY && a.maxY >= b.minY;
1626
+ }
1420
1627
  function nonzeroFillRule(paths) {
1421
1628
  const results = paths.map((_, i) => ({ index: i }));
1422
- const testPointsGroups = paths.map((path) => {
1629
+ const bboxes = [];
1630
+ const testPointsGroups = paths.map((path, pathIndex) => {
1423
1631
  const len = path.length;
1424
- if (!len) return [];
1632
+ if (!len) {
1633
+ bboxes[pathIndex] = null;
1634
+ return [];
1635
+ }
1425
1636
  let xMinYAuto = [Number.MAX_SAFE_INTEGER, 0];
1426
1637
  let xAutoYMin = [0, Number.MAX_SAFE_INTEGER];
1427
1638
  let xMaxYAuto = [Number.MIN_SAFE_INTEGER, 0];
@@ -1434,6 +1645,12 @@ function nonzeroFillRule(paths) {
1434
1645
  if (xMaxYAuto[0] < x) xMaxYAuto = [x, y];
1435
1646
  if (xAutoYMax[1] < y) xAutoYMax = [x, y];
1436
1647
  }
1648
+ bboxes[pathIndex] = {
1649
+ minX: xMinYAuto[0],
1650
+ minY: xAutoYMin[1],
1651
+ maxX: xMaxYAuto[0],
1652
+ maxY: xAutoYMax[1]
1653
+ };
1437
1654
  const mid = [(xMinYAuto[0] + xMaxYAuto[0]) / 2, (xAutoYMin[1] + xAutoYMax[1]) / 2];
1438
1655
  let xMidYMinDx;
1439
1656
  let xMidYMaxDx;
@@ -1479,13 +1696,16 @@ function nonzeroFillRule(paths) {
1479
1696
  for (let i = 0, len = paths.length; i < len; i++) {
1480
1697
  const _results = [];
1481
1698
  const testPoints = testPointsGroups[i];
1699
+ const boxI = bboxes[i];
1482
1700
  for (let j = 0; j < len; j++) {
1483
1701
  if (i === j) continue;
1702
+ const boxJ = bboxes[j];
1703
+ if (!boxI || !boxJ || !aabbIntersects(boxI, boxJ)) continue;
1484
1704
  const wnMap = {};
1485
1705
  const wnList = [];
1486
1706
  for (let p = 0, pLen = testPoints.length; p < pLen; p++) {
1487
1707
  const [x, y] = testPoints[p];
1488
- const winding = windingNumber(x, y, paths[j]);
1708
+ const winding = windingNumber$1(x, y, paths[j]);
1489
1709
  wnMap[winding] = (wnMap[winding] ?? 0) + 1;
1490
1710
  wnList.push(winding);
1491
1711
  }
@@ -1503,6 +1723,88 @@ function nonzeroFillRule(paths) {
1503
1723
  }
1504
1724
  return results;
1505
1725
  }
1726
+ function isLeft(ax, ay, bx, by, px, py) {
1727
+ return (bx - ax) * (py - ay) - (px - ax) * (by - ay);
1728
+ }
1729
+ function windingNumber(px, py, vertices) {
1730
+ const len = vertices.length;
1731
+ let wn = 0;
1732
+ for (let i = 0; i < len; i += 2) {
1733
+ const ax = vertices[i];
1734
+ const ay = vertices[i + 1];
1735
+ const k = (i + 2) % len;
1736
+ const bx = vertices[k];
1737
+ const by = vertices[k + 1];
1738
+ if (ay <= py) {
1739
+ if (by > py && isLeft(ax, ay, bx, by, px, py) > 0) wn++;
1740
+ } else if (by <= py && isLeft(ax, ay, bx, by, px, py) < 0) wn--;
1741
+ }
1742
+ return wn;
1743
+ }
1744
+ function crossingNumber(px, py, vertices) {
1745
+ const len = vertices.length;
1746
+ let cn = 0;
1747
+ for (let i = 0; i < len; i += 2) {
1748
+ const ax = vertices[i];
1749
+ const ay = vertices[i + 1];
1750
+ const k = (i + 2) % len;
1751
+ const bx = vertices[k];
1752
+ const by = vertices[k + 1];
1753
+ if (ay <= py && by > py || ay > py && by <= py) {
1754
+ if (px < ax + (py - ay) / (by - ay) * (bx - ax)) cn++;
1755
+ }
1756
+ }
1757
+ return cn;
1758
+ }
1759
+ function segmentDistance(px, py, ax, ay, bx, by) {
1760
+ const dx = bx - ax;
1761
+ const dy = by - ay;
1762
+ const lenSq = dx * dx + dy * dy;
1763
+ let t = lenSq === 0 ? 0 : ((px - ax) * dx + (py - ay) * dy) / lenSq;
1764
+ if (t < 0) t = 0;
1765
+ else if (t > 1) t = 1;
1766
+ const cx = ax + t * dx;
1767
+ const cy = ay + t * dy;
1768
+ return Math.hypot(px - cx, py - cy);
1769
+ }
1770
+ function pointInPolygon(point, vertices, fillRule = "nonzero") {
1771
+ if (vertices.length < 6) return false;
1772
+ if (fillRule === "evenodd") return (crossingNumber(point.x, point.y, vertices) & 1) === 1;
1773
+ return windingNumber(point.x, point.y, vertices) !== 0;
1774
+ }
1775
+ function pointInPolygons(point, polygons, fillRule = "nonzero") {
1776
+ const { x, y } = point;
1777
+ if (fillRule === "evenodd") {
1778
+ let cn = 0;
1779
+ for (let i = 0, len = polygons.length; i < len; i++) {
1780
+ const ring = polygons[i];
1781
+ if (ring.length >= 6) cn += crossingNumber(x, y, ring);
1782
+ }
1783
+ return (cn & 1) === 1;
1784
+ }
1785
+ let wn = 0;
1786
+ for (let i = 0, len = polygons.length; i < len; i++) {
1787
+ const ring = polygons[i];
1788
+ if (ring.length >= 6) wn += windingNumber(x, y, ring);
1789
+ }
1790
+ return wn !== 0;
1791
+ }
1792
+ function pointToPolylineDistance(point, vertices, closed = false) {
1793
+ const len = vertices.length;
1794
+ if (len < 2) return Infinity;
1795
+ const { x: px, y: py } = point;
1796
+ if (len === 2) return Math.hypot(px - vertices[0], py - vertices[1]);
1797
+ let min = Infinity;
1798
+ for (let i = 0; i < len - 2; i += 2) {
1799
+ const d = segmentDistance(px, py, vertices[i], vertices[i + 1], vertices[i + 2], vertices[i + 3]);
1800
+ if (d < min) min = d;
1801
+ }
1802
+ if (closed && len >= 6) {
1803
+ const d = segmentDistance(px, py, vertices[len - 2], vertices[len - 1], vertices[0], vertices[1]);
1804
+ if (d < min) min = d;
1805
+ }
1806
+ return min;
1807
+ }
1506
1808
  function quadraticBezierP0(t, p) {
1507
1809
  const k = 1 - t;
1508
1810
  return k * k * p;
@@ -2695,6 +2997,39 @@ var dataUri = "data:image/svg+xml;";
2695
2997
  var Curve = class {
2696
2998
  arcLengthDivision = 200;
2697
2999
  _lengths = [];
3000
+ _adaptiveCache;
3001
+ /**
3002
+ * Parent composite, set lazily when a composite caches its children. Lets
3003
+ * {@link invalidate} propagate up so an ancestor's caches refresh too.
3004
+ */
3005
+ _owner;
3006
+ _invalidating = false;
3007
+ /**
3008
+ * Drop cached arc lengths and the cached sampled outline used by hit testing, then
3009
+ * bubble up to {@link _owner}. Called automatically by {@link applyTransform} and the
3010
+ * `Path2D` mutators; call it manually after mutating control-point coordinates in place —
3011
+ * the caches cannot observe such mutations.
3012
+ */
3013
+ invalidate() {
3014
+ if (this._invalidating) return this;
3015
+ this._invalidating = true;
3016
+ this._invalidateSelf();
3017
+ this._owner?.invalidate();
3018
+ this._invalidating = false;
3019
+ return this;
3020
+ }
3021
+ /** Clears this curve's own caches. Composites also clear their children (see override). */
3022
+ _invalidateSelf() {
3023
+ this._lengths.length = 0;
3024
+ this._adaptiveCache = void 0;
3025
+ }
3026
+ /**
3027
+ * Sampled outline cached for repeated hit tests (read-only — do not mutate the result).
3028
+ * Invalidated by {@link invalidate}.
3029
+ */
3030
+ _getCachedAdaptiveVertices() {
3031
+ return this._adaptiveCache ??= this.getAdaptiveVertices();
3032
+ }
2698
3033
  getPointAt(u, output = new Vector2()) {
2699
3034
  return this.getPoint(this.getUToTMapping(u), output);
2700
3035
  }
@@ -2710,6 +3045,7 @@ var Curve = class {
2710
3045
  if (isFunction) transform(p);
2711
3046
  else transform.apply(p, p);
2712
3047
  });
3048
+ this.invalidate();
2713
3049
  return this;
2714
3050
  }
2715
3051
  getUnevenVertices(count = 5, output = []) {
@@ -2836,12 +3172,21 @@ var Curve = class {
2836
3172
  return mid;
2837
3173
  }
2838
3174
  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);
3175
+ const vertices = this.getAdaptiveVertices();
3176
+ let minX = min.x;
3177
+ let minY = min.y;
3178
+ let maxX = max.x;
3179
+ let maxY = max.y;
3180
+ for (let i = 0, len = vertices.length; i < len; i += 2) {
3181
+ const x = vertices[i];
3182
+ const y = vertices[i + 1];
3183
+ if (x < minX) minX = x;
3184
+ if (y < minY) minY = y;
3185
+ if (x > maxX) maxX = x;
3186
+ if (y > maxY) maxY = y;
2844
3187
  }
3188
+ min.set(minX, minY);
3189
+ max.set(maxX, maxY);
2845
3190
  return {
2846
3191
  min: min.finite(),
2847
3192
  max: max.finite()
@@ -2851,6 +3196,42 @@ var Curve = class {
2851
3196
  const { min, max } = this.getMinMax();
2852
3197
  return new BoundingBox(min.x, min.y, max.x - min.x, max.y - min.y);
2853
3198
  }
3199
+ /**
3200
+ * Test whether a point lies inside the area enclosed by this curve.
3201
+ *
3202
+ * The curve is sampled via {@link getAdaptiveVertices} into a single implicitly closed
3203
+ * ring. This is purely geometric (it ignores any `fill`/`stroke` style), mirroring
3204
+ * `CanvasRenderingContext2D.isPointInPath`.
3205
+ *
3206
+ * Composites that hold multiple sub-paths (e.g. {@link Path2D}) override this so holes
3207
+ * are honored — a single `Curve` is always one ring.
3208
+ */
3209
+ isPointInFill(point, options = {}) {
3210
+ return pointInPolygon(point, this._getCachedAdaptiveVertices(), options.fillRule);
3211
+ }
3212
+ /**
3213
+ * Test whether a point lies on this curve's stroke, i.e. within `strokeWidth / 2 + tolerance`
3214
+ * of the sampled outline. The point must be in the same coordinate space as the curve.
3215
+ *
3216
+ * Options: `strokeWidth` (path units, default `1`), `tolerance` (extra hit slack in path
3217
+ * units, default `0` — useful for thin strokes; no coordinate scaling is assumed, so convert
3218
+ * pixel tolerance to path units upstream if your path is normalized), and `closed` (whether
3219
+ * to include the closing edge from the last vertex back to the first).
3220
+ */
3221
+ isPointInStroke(point, options = {}) {
3222
+ const { strokeWidth = 1, tolerance = 0, closed = false } = options;
3223
+ return pointToPolylineDistance(point, this._getCachedAdaptiveVertices(), closed) <= strokeWidth / 2 + tolerance;
3224
+ }
3225
+ /**
3226
+ * Concise PathKit-style fill containment test: `contains(x, y)` is shorthand for
3227
+ * {@link isPointInFill} with a `{ x, y }` point.
3228
+ */
3229
+ contains(x, y, options = {}) {
3230
+ return this.isPointInFill({
3231
+ x,
3232
+ y
3233
+ }, options);
3234
+ }
2854
3235
  getFillVertices(_options) {
2855
3236
  return this.getAdaptiveVertices();
2856
3237
  }
@@ -2980,6 +3361,64 @@ var RoundCurve = class extends Curve {
2980
3361
  }
2981
3362
  return output.set(_x, _y);
2982
3363
  }
3364
+ /**
3365
+ * Point on the ellipse at an absolute angle (mirrors {@link getPoint}'s parameterization,
3366
+ * ignoring `_diff`).
3367
+ */
3368
+ _pointAtAngle(angle, output) {
3369
+ let x = this.cx + this.rx * Math.cos(angle);
3370
+ let y = this.cy + this.ry * Math.sin(angle);
3371
+ if (this.rotate !== 0) {
3372
+ const cos = Math.cos(this.rotate);
3373
+ const sin = Math.sin(this.rotate);
3374
+ const tx = x - this.cx;
3375
+ const ty = y - this.cy;
3376
+ x = tx * cos - ty * sin + this.cx;
3377
+ y = tx * sin + ty * cos + this.cy;
3378
+ }
3379
+ return output.set(x, y);
3380
+ }
3381
+ /**
3382
+ * Analytical bounds of the (elliptical) arc: the start/end points plus the per-axis
3383
+ * extrema angles that fall within the swept interval. Matches {@link getPoint}, so it is
3384
+ * exact for `ArcCurve`/`EllipseCurve`. The `_diff` offset (used only by the legacy
3385
+ * `_getAdaptiveVerticesByCircle` path) is intentionally ignored here.
3386
+ */
3387
+ getMinMax(min = Vector2.MAX, max = Vector2.MIN) {
3388
+ const { startAngle, rotate } = this;
3389
+ const delta = this._getDeltaAngle();
3390
+ const cosT = Math.cos(rotate);
3391
+ const sinT = Math.sin(rotate);
3392
+ const p = tempV2;
3393
+ let minX = min.x;
3394
+ let minY = min.y;
3395
+ let maxX = max.x;
3396
+ let maxY = max.y;
3397
+ const consider = (angle) => {
3398
+ this._pointAtAngle(angle, p);
3399
+ if (p.x < minX) minX = p.x;
3400
+ if (p.y < minY) minY = p.y;
3401
+ if (p.x > maxX) maxX = p.x;
3402
+ if (p.y > maxY) maxY = p.y;
3403
+ };
3404
+ consider(startAngle);
3405
+ consider(startAngle + delta);
3406
+ const ax = Math.atan2(-this.ry * sinT, this.rx * cosT);
3407
+ const ay = Math.atan2(this.ry * cosT, this.rx * sinT);
3408
+ const bases = [
3409
+ ax,
3410
+ ax + Math.PI,
3411
+ ay,
3412
+ ay + Math.PI
3413
+ ];
3414
+ for (let i = 0; i < 4; i++) if (angleInSweep(bases[i], startAngle, delta)) consider(bases[i]);
3415
+ min.set(minX, minY);
3416
+ max.set(maxX, maxY);
3417
+ return {
3418
+ min: min.finite(),
3419
+ max: max.finite()
3420
+ };
3421
+ }
2983
3422
  toCommands() {
2984
3423
  const { cx, cy, rx, ry, startAngle, endAngle, clockwise, rotate } = this;
2985
3424
  const startX = cx + rx * Math.cos(startAngle) * Math.cos(rotate) - ry * Math.sin(startAngle) * Math.sin(rotate);
@@ -3050,6 +3489,7 @@ var RoundCurve = class extends Curve {
3050
3489
  this.cy = tempV2.y;
3051
3490
  if (isTransformSkewed(transform)) transfEllipseGeneric(this, transform);
3052
3491
  else transfEllipseNoSkew(this, transform);
3492
+ this.invalidate();
3053
3493
  return this;
3054
3494
  }
3055
3495
  getControlPointRefs() {
@@ -3179,6 +3619,18 @@ var RoundCurve = class extends Curve {
3179
3619
  return this;
3180
3620
  }
3181
3621
  };
3622
+ function angleInSweep(a, start, delta) {
3623
+ const PI_2 = Math.PI * 2;
3624
+ const eps = 1e-9;
3625
+ if (Math.abs(delta) >= PI_2 - eps) return true;
3626
+ let off = (a - start) % PI_2;
3627
+ if (delta >= 0) {
3628
+ if (off < -1e-9) off += PI_2;
3629
+ return off >= -1e-9 && off <= delta + eps;
3630
+ }
3631
+ if (off > eps) off -= PI_2;
3632
+ return off <= eps && off >= delta - eps;
3633
+ }
3182
3634
  function transfEllipseGeneric(curve, m) {
3183
3635
  const a = curve.rx;
3184
3636
  const b = curve.ry;
@@ -3379,6 +3831,22 @@ var CompositeCurve = class CompositeCurve extends Curve {
3379
3831
  super();
3380
3832
  this.curves = curves;
3381
3833
  }
3834
+ _adaptiveCacheLen = -1;
3835
+ _invalidateSelf() {
3836
+ super._invalidateSelf();
3837
+ this._adaptiveCacheLen = -1;
3838
+ this.curves.forEach((curve) => curve.invalidate());
3839
+ }
3840
+ _getCachedAdaptiveVertices() {
3841
+ if (!this._adaptiveCache || this._adaptiveCacheLen !== this.curves.length) {
3842
+ this.curves.forEach((curve) => {
3843
+ curve._owner = this;
3844
+ });
3845
+ this._adaptiveCache = this.getAdaptiveVertices();
3846
+ this._adaptiveCacheLen = this.curves.length;
3847
+ }
3848
+ return this._adaptiveCache;
3849
+ }
3382
3850
  getFlatCurves() {
3383
3851
  return this.curves.flatMap((curve) => {
3384
3852
  if (curve instanceof CompositeCurve) return curve.getFlatCurves();
@@ -3413,6 +3881,7 @@ var CompositeCurve = class CompositeCurve extends Curve {
3413
3881
  updateLengths() {
3414
3882
  const lengths = [];
3415
3883
  for (let i = 0, sum = 0, len = this.curves.length; i < len; i++) {
3884
+ this.curves[i]._owner = this;
3416
3885
  sum += this.curves[i].getLength();
3417
3886
  lengths.push(sum);
3418
3887
  }
@@ -3466,7 +3935,10 @@ var CompositeCurve = class CompositeCurve extends Curve {
3466
3935
  }
3467
3936
  }
3468
3937
  applyTransform(transform) {
3938
+ this._invalidating = true;
3469
3939
  this.curves.forEach((curve) => curve.applyTransform(transform));
3940
+ this._invalidating = false;
3941
+ this.invalidate();
3470
3942
  return this;
3471
3943
  }
3472
3944
  getMinMax(min = Vector2.MAX, max = Vector2.MIN) {
@@ -3723,7 +4195,7 @@ var RectangleCurve = class extends PolygonCurve {
3723
4195
  return this;
3724
4196
  }
3725
4197
  };
3726
- var RoundRectangleCurve = class extends RoundCurve {
4198
+ var RoundRectangleCurve = class extends CompositeCurve {
3727
4199
  constructor(x = 0, y = 0, width = 1, height = 1, radius = 1) {
3728
4200
  super();
3729
4201
  this.x = x;
@@ -3734,25 +4206,44 @@ var RoundRectangleCurve = class extends RoundCurve {
3734
4206
  this.update();
3735
4207
  }
3736
4208
  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);
4209
+ const { x, y, width, height } = this;
4210
+ const r = Math.max(0, Math.min(this.radius, Math.abs(width) / 2, Math.abs(height) / 2));
4211
+ const x0 = x;
4212
+ const x1 = x + r;
4213
+ const x2 = x + width - r;
4214
+ const x3 = x + width;
4215
+ const y0 = y;
4216
+ const y1 = y + r;
4217
+ const y2 = y + height - r;
4218
+ const y3 = y + height;
4219
+ if (r <= 0) this.curves = [
4220
+ LineCurve.from(x0, y0, x3, y0),
4221
+ LineCurve.from(x3, y0, x3, y3),
4222
+ LineCurve.from(x3, y3, x0, y3),
4223
+ LineCurve.from(x0, y3, x0, y0)
4224
+ ];
4225
+ else {
4226
+ const HALF_PI = Math.PI / 2;
4227
+ this.curves = [
4228
+ LineCurve.from(x1, y0, x2, y0),
4229
+ new ArcCurve(x2, y1, r, -HALF_PI, 0, true),
4230
+ LineCurve.from(x3, y1, x3, y2),
4231
+ new ArcCurve(x2, y2, r, 0, HALF_PI, true),
4232
+ LineCurve.from(x2, y3, x1, y3),
4233
+ new ArcCurve(x1, y2, r, HALF_PI, Math.PI, true),
4234
+ LineCurve.from(x0, y2, x0, y1),
4235
+ new ArcCurve(x1, y1, r, Math.PI, Math.PI * 1.5, true)
4236
+ ];
4237
+ }
4238
+ this.invalidate();
3747
4239
  return this;
3748
4240
  }
3749
4241
  drawTo(ctx) {
3750
- const { x, y, width, height, radius } = this;
3751
- ctx.roundRect(x, y, width, height, radius);
4242
+ ctx.roundRect(this.x, this.y, this.width, this.height, this.radius);
3752
4243
  return this;
3753
4244
  }
3754
4245
  copyFrom(source) {
3755
- super.copyFrom(source);
4246
+ this.arcLengthDivision = source.arcLengthDivision;
3756
4247
  this.x = source.x;
3757
4248
  this.y = source.y;
3758
4249
  this.width = source.width;
@@ -3829,6 +4320,16 @@ var CurvePath = class extends CompositeCurve {
3829
4320
  getFillVertices(options) {
3830
4321
  return this._closeVertices(super.getFillVertices(options));
3831
4322
  }
4323
+ /**
4324
+ * Same as {@link Curve.isPointInStroke}, but `closed` defaults to this sub-path's actual
4325
+ * closed-ness: explicitly `autoClose`, or geometrically closed (first vertex === last).
4326
+ */
4327
+ isPointInStroke(point, options = {}) {
4328
+ const { strokeWidth = 1, tolerance = 0 } = options;
4329
+ const vertices = this._getCachedAdaptiveVertices();
4330
+ const len = vertices.length;
4331
+ return pointToPolylineDistance(point, vertices, options.closed ?? (this.autoClose || len >= 6 && vertices[0] === vertices[len - 2] && vertices[1] === vertices[len - 1])) <= strokeWidth / 2 + tolerance;
4332
+ }
3832
4333
  _setCurrentPoint(point) {
3833
4334
  this.currentPoint = new Vector2(point.x, point.y);
3834
4335
  if (!this.startPoint) this.startPoint = this.currentPoint.clone();
@@ -3966,6 +4467,8 @@ var CurvePath = class extends CompositeCurve {
3966
4467
  };
3967
4468
  var Path2D = class Path2D extends CompositeCurve {
3968
4469
  _meta;
4470
+ _ringsCache;
4471
+ _ringsCacheLen = -1;
3969
4472
  currentCurve = new CurvePath();
3970
4473
  style;
3971
4474
  get startPoint() {
@@ -4077,6 +4580,7 @@ var Path2D = class Path2D extends CompositeCurve {
4077
4580
  this.getControlPointRefs().forEach((point) => {
4078
4581
  point.scale(sx, sy, target);
4079
4582
  });
4583
+ this.invalidate();
4080
4584
  return this;
4081
4585
  }
4082
4586
  skew(ax, ay = 0, target = {
@@ -4086,6 +4590,7 @@ var Path2D = class Path2D extends CompositeCurve {
4086
4590
  this.getControlPointRefs().forEach((point) => {
4087
4591
  point.skew(ax, ay, target);
4088
4592
  });
4593
+ this.invalidate();
4089
4594
  return this;
4090
4595
  }
4091
4596
  rotate(rad, target = {
@@ -4095,6 +4600,7 @@ var Path2D = class Path2D extends CompositeCurve {
4095
4600
  this.getControlPointRefs().forEach((point) => {
4096
4601
  point.rotate(rad, target);
4097
4602
  });
4603
+ this.invalidate();
4098
4604
  return this;
4099
4605
  }
4100
4606
  bold(b) {
@@ -4140,47 +4646,67 @@ var Path2D = class Path2D extends CompositeCurve {
4140
4646
  }
4141
4647
  });
4142
4648
  });
4649
+ this.invalidate();
4143
4650
  return this;
4144
4651
  }
4652
+ /**
4653
+ * Test whether a point lies inside the filled area of this path.
4654
+ *
4655
+ * Each sub-path ({@link CurvePath}) is sampled into its own ring and all rings are
4656
+ * evaluated together via {@link pointInPolygons}, so holes (donut / hollow shapes) are
4657
+ * honored. This is purely geometric and ignores `style.fill` — for the `fill: 'none'`
4658
+ * fallback, gate the call upstream (see {@link Path2DSet.hitTest}).
4659
+ *
4660
+ * Defaults `fillRule` to `style.fillRule`, then `'nonzero'` (matching SVG/Canvas).
4661
+ */
4662
+ _invalidateSelf() {
4663
+ super._invalidateSelf();
4664
+ this._ringsCache = void 0;
4665
+ this._ringsCacheLen = -1;
4666
+ }
4667
+ /** Per-sub-path sampled rings, cached for repeated hit tests. */
4668
+ _getRings() {
4669
+ if (!this._ringsCache || this._ringsCacheLen !== this.curves.length) {
4670
+ this._ringsCache = this.curves.map((curve) => {
4671
+ curve._owner = this;
4672
+ return curve.getAdaptiveVertices();
4673
+ });
4674
+ this._ringsCacheLen = this.curves.length;
4675
+ }
4676
+ return this._ringsCache;
4677
+ }
4678
+ isPointInFill(point, options = {}) {
4679
+ const fillRule = options.fillRule ?? this.style.fillRule ?? "nonzero";
4680
+ return pointInPolygons(point, this._getRings(), fillRule);
4681
+ }
4682
+ /**
4683
+ * Test whether a point lies on this path's stroke. A hit on any sub-path counts.
4684
+ *
4685
+ * Defaults `strokeWidth` to this path's own {@link strokeWidth} (which is `0` when
4686
+ * `style.stroke` is `'none'`). Each sub-path infers its own closed-ness unless `closed`
4687
+ * is given explicitly.
4688
+ */
4689
+ isPointInStroke(point, options = {}) {
4690
+ const strokeWidth = options.strokeWidth ?? this.strokeWidth;
4691
+ const { tolerance = 0, closed } = options;
4692
+ return this.curves.some((curve) => curve.isPointInStroke(point, {
4693
+ strokeWidth,
4694
+ tolerance,
4695
+ closed
4696
+ }));
4697
+ }
4145
4698
  getMinMax(min = Vector2.MAX, max = Vector2.MIN, withStyle = true) {
4146
- const strokeWidth = this.strokeWidth;
4147
4699
  this.curves.forEach((curve) => {
4148
4700
  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
4701
  });
4702
+ if (withStyle) {
4703
+ const strokeWidth = this.strokeWidth;
4704
+ if (strokeWidth > 1 && Number.isFinite(min.x)) {
4705
+ const half = strokeWidth / 2;
4706
+ min.set(min.x - half, min.y - half);
4707
+ max.set(max.x + half, max.y + half);
4708
+ }
4709
+ }
4184
4710
  return {
4185
4711
  min: min.finite(),
4186
4712
  max: max.finite()
@@ -4680,7 +5206,7 @@ var YDoc = class extends Observable {
4680
5206
  this.transact(() => {
4681
5207
  const childId = child.id;
4682
5208
  this._debug(`[removeChild][${childId}]`, child.name, oldIndex);
4683
- const index = childrenIds.toJSON().indexOf(childId);
5209
+ const index = childrenIds.toArray().indexOf(childId);
4684
5210
  if (index > -1) childrenIds.delete(index, 1);
4685
5211
  });
4686
5212
  });
@@ -4936,6 +5462,7 @@ var _0_context_default = defineMixin((editor, options) => {
4936
5462
  const textSelection = ref();
4937
5463
  const hoverElement = ref();
4938
5464
  const state = ref();
5465
+ const mode = ref("canvas");
4939
5466
  function setCursor(mode) {
4940
5467
  renderEngine.value.input.setCursor(mode);
4941
5468
  }
@@ -5030,6 +5557,7 @@ var _0_context_default = defineMixin((editor, options) => {
5030
5557
  drawboardPointer,
5031
5558
  drawboardContextMenuPointer,
5032
5559
  state,
5560
+ mode,
5033
5561
  setCursor,
5034
5562
  getGlobalPointer,
5035
5563
  parseAnchor,
@@ -5072,8 +5600,16 @@ var _0_context_default = defineMixin((editor, options) => {
5072
5600
  const { left = _left, top = _top } = drawboardDom.value?.getBoundingClientRect() ?? {};
5073
5601
  drawboardAabb.value = new Aabb2D(left, top, width, height);
5074
5602
  });
5603
+ let pointerRafId = null;
5604
+ let lastPointerEvent;
5075
5605
  function onMouseMove(event) {
5076
- drawboardPointer.value = new Vector2(event.clientX - drawboardAabb.value.left, event.clientY - drawboardAabb.value.top);
5606
+ lastPointerEvent = event;
5607
+ if (pointerRafId !== null) return;
5608
+ pointerRafId = requestAnimationFrame(() => {
5609
+ pointerRafId = null;
5610
+ const e = lastPointerEvent;
5611
+ drawboardPointer.value = new Vector2(e.clientX - drawboardAabb.value.left, e.clientY - drawboardAabb.value.top);
5612
+ });
5077
5613
  }
5078
5614
  onBeforeMount(() => {
5079
5615
  on("docSet", onSetDoc);
@@ -5084,6 +5620,7 @@ var _0_context_default = defineMixin((editor, options) => {
5084
5620
  off("docSet", onSetDoc);
5085
5621
  renderEngine.value.stop();
5086
5622
  document.removeEventListener("mousemove", onMouseMove);
5623
+ if (pointerRafId !== null) cancelAnimationFrame(pointerRafId);
5087
5624
  });
5088
5625
  };
5089
5626
  });
@@ -5153,6 +5690,10 @@ var en_default = {
5153
5690
  "ellipse": "Ellipse",
5154
5691
  "polygon": "Polygon",
5155
5692
  "star": "Star",
5693
+ "table": "Table",
5694
+ "chartBar": "Bar Chart",
5695
+ "chartLine": "Line Chart",
5696
+ "chartPie": "Pie Chart",
5156
5697
  "image": "Image",
5157
5698
  "video": "Video",
5158
5699
  "lottie": "Lottie",
@@ -5166,11 +5707,6 @@ var en_default = {
5166
5707
  "saveAs:png": "Save as PNG",
5167
5708
  "saveAs:jpeg": "Save as JPEG",
5168
5709
  "saveAs:webp": "Save as WEBP",
5169
- "saveAs:svg": "Save as SVG",
5170
- "saveAs:gif": "Save as GIF",
5171
- "saveAs:mp4": "Save as MP4",
5172
- "saveAs:pdf": "Save as PDF",
5173
- "saveAs:pptx": "Save as PPTX",
5174
5710
  "saveAs:json": "Save as JSON",
5175
5711
  "addSubNode": "Add sub node",
5176
5712
  "edit": "Edit",
@@ -5193,6 +5729,9 @@ var en_default = {
5193
5729
  "selectPreviousSibling": "Select previous sibling",
5194
5730
  "selectNextSibling": "Select next sibling",
5195
5731
  "view": "View",
5732
+ "mode": "Mode",
5733
+ "mode:canvas": "Canvas mode",
5734
+ "mode:workflow": "Workflow mode",
5196
5735
  "checkerboard": "Checkerboard",
5197
5736
  "pixelGrid": "Pixel grid",
5198
5737
  "ruler": "Ruler",
@@ -5282,6 +5821,10 @@ var zh_Hans_default = {
5282
5821
  "ellipse": "椭圆",
5283
5822
  "polygon": "多边形",
5284
5823
  "star": "星形",
5824
+ "table": "表格",
5825
+ "chartBar": "柱状图",
5826
+ "chartLine": "折线图",
5827
+ "chartPie": "饼图",
5285
5828
  "image": "图片",
5286
5829
  "video": "视频",
5287
5830
  "lottie": "Lottie",
@@ -5295,11 +5838,6 @@ var zh_Hans_default = {
5295
5838
  "saveAs:png": "另存为 PNG",
5296
5839
  "saveAs:jpeg": "另存为 JPEG",
5297
5840
  "saveAs:webp": "另存为 WEBP",
5298
- "saveAs:svg": "另存为 SVG",
5299
- "saveAs:gif": "另存为 GIF",
5300
- "saveAs:mp4": "另存为 MP4",
5301
- "saveAs:pdf": "另存为 PDF",
5302
- "saveAs:pptx": "另存为 PPTX",
5303
5841
  "saveAs:json": "另存为 JSON",
5304
5842
  "addSubNode": "添加子节点",
5305
5843
  "edit": "编辑",
@@ -5322,6 +5860,9 @@ var zh_Hans_default = {
5322
5860
  "selectPreviousSibling": "选择前一个",
5323
5861
  "selectNextSibling": "选择后一个",
5324
5862
  "view": "视图",
5863
+ "mode": "模式",
5864
+ "mode:canvas": "画布模式",
5865
+ "mode:workflow": "工作流模式",
5325
5866
  "checkerboard": "棋盘",
5326
5867
  "pixelGrid": "像素网格",
5327
5868
  "ruler": "标尺",
@@ -5382,6 +5923,10 @@ var zh_Hans_default = {
5382
5923
  //#region src/mixins/0.locale.ts
5383
5924
  var _0_locale_default = defineMixin((editor, options) => {
5384
5925
  const { locale } = options;
5926
+ const pluginMessages = ref({});
5927
+ function registerMessages(value) {
5928
+ pluginMessages.value = merge({}, pluginMessages.value, value);
5929
+ }
5385
5930
  const messages = computed(() => {
5386
5931
  const { locale: _locale, fallback: _fallback, messages = {} } = merge({
5387
5932
  locale: "en",
@@ -5393,8 +5938,8 @@ var _0_locale_default = defineMixin((editor, options) => {
5393
5938
  }, locale);
5394
5939
  return {
5395
5940
  locale: _locale,
5396
- localeMessages: messages[_locale],
5397
- fallbackMessages: messages[_fallback]
5941
+ localeMessages: merge({}, messages[_locale], pluginMessages.value[_locale]),
5942
+ fallbackMessages: merge({}, messages[_fallback], pluginMessages.value[_fallback])
5398
5943
  };
5399
5944
  });
5400
5945
  function t(key, fallback) {
@@ -5403,7 +5948,10 @@ var _0_locale_default = defineMixin((editor, options) => {
5403
5948
  if (value === void 0) console.warn(`[mce] Not found '${key}' key in '${locale}' locale messages.`);
5404
5949
  return value ?? key ?? fallback ?? "";
5405
5950
  }
5406
- Object.assign(editor, { t });
5951
+ Object.assign(editor, {
5952
+ t,
5953
+ registerMessages
5954
+ });
5407
5955
  });
5408
5956
  //#endregion
5409
5957
  //#region src/mixins/1.frame.ts
@@ -5525,10 +6073,17 @@ var _1_timeline_default = defineMixin((editor) => {
5525
6073
  //#endregion
5526
6074
  //#region src/mixins/1.upload.ts
5527
6075
  var _1_upload_default = defineMixin((editor, options) => {
6076
+ const objectUrls = /* @__PURE__ */ new Set();
5528
6077
  const upload = async (file) => {
5529
6078
  if (options.customUpload) return await options.customUpload(file);
5530
- return URL.createObjectURL(file);
6079
+ const url = URL.createObjectURL(file);
6080
+ objectUrls.add(url);
6081
+ return url;
5531
6082
  };
6083
+ editor.on("docSet", () => {
6084
+ objectUrls.forEach((url) => URL.revokeObjectURL(url));
6085
+ objectUrls.clear();
6086
+ });
5532
6087
  Object.assign(editor, { upload });
5533
6088
  });
5534
6089
  //#endregion
@@ -5639,11 +6194,13 @@ var _2_box_default = defineMixin((editor) => {
5639
6194
  };
5640
6195
  node.forEach((child) => {
5641
6196
  if (isElement(child)) {
5642
- const aabb = getAabb(child);
5643
- min.x = Math.min(min.x, aabb.left);
5644
- min.y = Math.min(min.y, aabb.top);
5645
- max.x = Math.max(max.x, aabb.left + aabb.width);
5646
- max.y = Math.max(max.y, aabb.top + aabb.height);
6197
+ const style = child.style;
6198
+ style.left, style.top, style.width, style.height, style.rotate;
6199
+ const box = child.globalAabb;
6200
+ min.x = Math.min(min.x, box.left);
6201
+ min.y = Math.min(min.y, box.top);
6202
+ max.x = Math.max(max.x, box.left + box.width);
6203
+ max.y = Math.max(max.y, box.top + box.height);
5647
6204
  }
5648
6205
  });
5649
6206
  aabb = new Aabb2D(min.x, min.y, max.x - min.x, max.y - min.y);
@@ -6194,9 +6751,9 @@ var hotkey_default = defineMixin((editor) => {
6194
6751
  getKbd
6195
6752
  });
6196
6753
  return () => {
6197
- const { exec } = editor;
6754
+ const { exec, state } = editor;
6198
6755
  useEventListener(isClient ? window : void 0, "keydown", (e) => {
6199
- if (isInputEvent(e)) return;
6756
+ if (isInputEvent(e) || state.value === "typing") return;
6200
6757
  const eKey = parseKeyboardEvent(e);
6201
6758
  hotkeysData.value.forEach((hotkeyData) => {
6202
6759
  if (hotkeyData.enabled === false) return;
@@ -6258,186 +6815,241 @@ function createHttp() {
6258
6815
  }
6259
6816
  return { request };
6260
6817
  }
6818
+ var http_default = defineMixin((editor, options) => {
6819
+ Object.assign(editor, { http: options.http ?? createHttp() });
6820
+ });
6261
6821
  //#endregion
6262
- //#region src/mixins/index.ts
6263
- var mixins = [
6264
- _0_command_default,
6265
- _0_config_default,
6266
- base_default,
6267
- _0_context_default,
6268
- _0_font_default,
6269
- _0_locale_default,
6270
- _1_frame_default,
6271
- _1_screen_default,
6272
- _1_timeline_default,
6273
- _1_upload_default,
6274
- _2_box_default,
6275
- _4_0_node_default,
6276
- _4_2_frame_default,
6277
- _4_3_element_default,
6278
- exporter_default,
6279
- 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;
6822
+ //#region src/mixins/loader.ts
6823
+ var loader_default = defineMixin((editor) => {
6824
+ const { state } = editor;
6825
+ const loaders = reactive(/* @__PURE__ */ new Map());
6826
+ const registerLoader = (value) => {
6827
+ if (Array.isArray(value)) value.forEach((v) => registerLoader(v));
6828
+ else loaders.set(value.name, value);
6829
+ };
6830
+ const unregisterLoader = (key) => {
6831
+ loaders.delete(key);
6832
+ };
6833
+ const canLoad = async (source) => {
6834
+ for (const loader of loaders.values()) if (await loader.test(source)) return true;
6835
+ return false;
6836
+ };
6837
+ const load = async (source) => {
6838
+ state.value = "loading";
6839
+ const items = [];
6840
+ let hasLoader = false;
6841
+ try {
6842
+ for (const loader of loaders.values()) if (await loader.test(source)) {
6843
+ const res = await loader.load(source);
6844
+ if (Array.isArray(res)) items.push(...res);
6845
+ else items.push(res);
6846
+ hasLoader = true;
6847
+ break;
6311
6848
  }
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();
6849
+ } finally {
6850
+ state.value = void 0;
6851
+ }
6852
+ if (!hasLoader) throw new Error(`Failed to load source "${source}"`);
6853
+ return items;
6854
+ };
6855
+ const openFileDialog = (options = {}) => {
6856
+ const { multiple = false } = options;
6857
+ return new Promise((resolve) => {
6858
+ const accepts = [];
6859
+ for (const loader of loaders.values()) if (loader.accept) accepts.push(loader.accept);
6860
+ const { onChange, open } = useFileDialog({
6861
+ accept: accepts.join(","),
6862
+ reset: true,
6863
+ multiple
6327
6864
  });
6328
- };
6329
- Object.assign(editor, {
6330
- loaders,
6331
- registerLoader,
6332
- unregisterLoader,
6333
- canLoad,
6334
- load,
6335
- openFileDialog
6865
+ onChange((files) => resolve(files ? Array.from(files) : []));
6866
+ open();
6336
6867
  });
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
- }
6868
+ };
6869
+ Object.assign(editor, {
6870
+ loaders,
6871
+ registerLoader,
6872
+ unregisterLoader,
6873
+ canLoad,
6874
+ load,
6875
+ openFileDialog
6876
+ });
6877
+ });
6878
+ //#endregion
6879
+ //#region src/mixins/snapper.ts
6880
+ var snapper_default = defineMixin((editor) => {
6881
+ const { camera } = editor;
6882
+ const snappers = reactive(/* @__PURE__ */ new Map());
6883
+ const snapThreshold = computed(() => Math.max(1, 5 / camera.value.zoom.x));
6884
+ const registerSnapper = (key, snapper) => {
6885
+ snappers.set(key, snapper);
6886
+ };
6887
+ const unregisterSnapper = (key) => {
6888
+ snappers.delete(key);
6889
+ };
6890
+ const snap = (box) => {
6891
+ const axisX = /* @__PURE__ */ new Set();
6892
+ const axisY = /* @__PURE__ */ new Set();
6893
+ snappers.forEach((snapper) => {
6894
+ const { xLines, yLines } = snapper.getLines();
6895
+ xLines?.forEach((v) => axisX.add(v));
6896
+ yLines?.forEach((v) => axisY.add(v));
6897
+ });
6898
+ const posList = [
6899
+ [0, "x"],
6900
+ [box.width / 2, "x"],
6901
+ [box.width, "x"],
6902
+ [0, "y"],
6903
+ [box.height / 2, "y"],
6904
+ [box.height, "y"]
6905
+ ];
6906
+ for (let i = 0; i < posList.length; i++) {
6907
+ const [offset, axis] = posList[i];
6908
+ let position;
6909
+ let numArray;
6910
+ if (axis === "x") {
6911
+ position = box.left + offset;
6912
+ numArray = axisX;
6913
+ } else {
6914
+ position = box.top + offset;
6915
+ numArray = axisY;
6916
+ }
6917
+ let closest;
6918
+ let minDist = Infinity;
6919
+ for (const num of numArray) {
6920
+ const dist = num - position;
6921
+ const absDist = Math.abs(dist);
6922
+ if (absDist < minDist) {
6923
+ minDist = absDist;
6924
+ closest = num;
6384
6925
  }
6385
- if (minDist < snapThreshold.value) position = closest ?? position;
6386
- if (axis === "x") box.left = position - offset;
6387
- else box.top = position - offset;
6388
6926
  }
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
- }));
6927
+ if (minDist < snapThreshold.value) position = closest ?? position;
6928
+ if (axis === "x") box.left = position - offset;
6929
+ else box.top = position - offset;
6422
6930
  }
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
- }
6931
+ };
6932
+ Object.assign(editor, {
6933
+ snappers,
6934
+ registerSnapper,
6935
+ unregisterSnapper,
6936
+ snap
6937
+ });
6938
+ });
6939
+ //#endregion
6940
+ //#region src/mixins/snapshot.ts
6941
+ var snapshot_default = defineMixin((editor) => {
6942
+ const { isElement, frames, frameThumbs, log, fonts, runExclusiveRender } = editor;
6943
+ async function snapshot() {
6944
+ frameThumbs.value = frames.value.map(() => ({
6945
+ instanceId: -1,
6946
+ width: 0,
6947
+ height: 0,
6948
+ url: ""
6949
+ }));
6950
+ for (let i = 0; i < frames.value.length; i++) await captureFrameScreenshot(i);
6951
+ }
6952
+ async function captureElementScreenshot(element) {
6953
+ await editor.waitUntilFontLoad();
6954
+ let data;
6955
+ if (isElement(element)) data = element.toJSON();
6956
+ else data = { ...element };
6957
+ data.style ??= {};
6958
+ data.style.top = 0;
6959
+ data.style.left = 0;
6960
+ return await runExclusiveRender(() => render({
6961
+ width: data.style.width,
6962
+ height: data.style.height,
6963
+ fonts,
6964
+ data
6965
+ }));
6966
+ }
6967
+ async function captureFrameScreenshot(index) {
6968
+ const frame = frames.value[index];
6969
+ if (frame) {
6970
+ const canvas = await captureElementScreenshot(frame);
6971
+ frameThumbs.value[index] = {
6972
+ instanceId: frame.instanceId,
6973
+ width: canvas.width,
6974
+ height: canvas.height,
6975
+ url: canvas.toDataURL()
6976
+ };
6977
+ log("captureFrameScreenshot", index);
6435
6978
  }
6436
- Object.assign(editor, {
6437
- snapshot,
6438
- captureElementScreenshot,
6439
- captureFrameScreenshot
6440
- });
6979
+ }
6980
+ Object.assign(editor, {
6981
+ snapshot,
6982
+ captureElementScreenshot,
6983
+ captureFrameScreenshot
6984
+ });
6985
+ });
6986
+ //#endregion
6987
+ //#region src/composables/strategy.ts
6988
+ var makeMceStrategyProps = propsFactory({
6989
+ resizeStrategy: Function,
6990
+ activeStrategy: Function,
6991
+ doubleclickStrategy: Function,
6992
+ hoverStrategy: Function
6993
+ }, "makeMceStrategyProps");
6994
+ var defaultActiveStrategy = (context) => {
6995
+ const { element, editor } = context;
6996
+ if (!element) return;
6997
+ const { isRootNode, inEditorIs, isElement, elementSelection } = editor;
6998
+ const activeElement = elementSelection.value[0];
6999
+ const cb = (node) => {
7000
+ const parent = node.parent;
7001
+ 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;
7002
+ return false;
7003
+ };
7004
+ if (cb(element)) return element;
7005
+ return element.findAncestor(cb);
7006
+ };
7007
+ var defaultDoubleclickStrategy = (context) => {
7008
+ context.editor.exec("enter");
7009
+ };
7010
+ var defaultHoverStrategy = (context) => {
7011
+ const { element, editor } = context;
7012
+ if (!element) return;
7013
+ const { isRootNode, inEditorIs, isElement, elementSelection } = editor;
7014
+ const activeElement = elementSelection.value[0];
7015
+ const cb = (node) => {
7016
+ const parent = node.parent;
7017
+ 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;
7018
+ return false;
7019
+ };
7020
+ if (cb(element)) return element;
7021
+ return element.findAncestor(cb);
7022
+ };
7023
+ //#endregion
7024
+ //#region src/mixins/index.ts
7025
+ var mixins = [
7026
+ _0_command_default,
7027
+ _0_config_default,
7028
+ base_default,
7029
+ _0_context_default,
7030
+ _0_font_default,
7031
+ _0_locale_default,
7032
+ _1_frame_default,
7033
+ _1_screen_default,
7034
+ _1_timeline_default,
7035
+ _1_upload_default,
7036
+ _2_box_default,
7037
+ _4_0_node_default,
7038
+ _4_2_frame_default,
7039
+ _4_3_element_default,
7040
+ exporter_default,
7041
+ hotkey_default,
7042
+ http_default,
7043
+ loader_default,
7044
+ snapper_default,
7045
+ snapshot_default,
7046
+ defineMixin((_editor, options) => {
7047
+ return {
7048
+ activeStrategy: options.activeStrategy ?? defaultActiveStrategy,
7049
+ doubleclickStrategy: options.doubleclickStrategy ?? defaultDoubleclickStrategy,
7050
+ hoverStrategy: options.hoverStrategy ?? defaultHoverStrategy,
7051
+ resizeStrategy: options.resizeStrategy
7052
+ };
6441
7053
  }),
6442
7054
  defineMixin((editor) => {
6443
7055
  const { state } = editor;
@@ -6713,6 +7325,7 @@ var autoNest_default = definePlugin((editor) => {
6713
7325
  const { getGlobalPointer, frames, isFrameNode, exec, root, elementSelection } = editor;
6714
7326
  let context;
6715
7327
  function nestIntoFrame(el, options) {
7328
+ if (el.meta?.inEditorIs?.startsWith("Workflow")) return;
6716
7329
  const pointer = options?.pointer;
6717
7330
  const frame1 = el.findAncestor((node) => isFrameNode(node, true));
6718
7331
  const aabb1 = el.globalAabb;
@@ -6936,7 +7549,7 @@ var doc_default = definePlugin((editor, options) => {
6936
7549
  //#endregion
6937
7550
  //#region src/plugins/edit.ts
6938
7551
  var edit_default = definePlugin((editor, options) => {
6939
- const { state, selection, exec, canLoad, load, addElements, hoverElement, to, exporters } = editor;
7552
+ const { state, selection, exec, canLoad, load, addElements, hoverElement, to, exporters, renderEngine } = editor;
6940
7553
  const copiedData = ref();
6941
7554
  const useClipboard = options.clipboard !== false && SUPPORTS_CLIPBOARD;
6942
7555
  const cancel = () => {
@@ -6944,6 +7557,19 @@ var edit_default = definePlugin((editor, options) => {
6944
7557
  };
6945
7558
  const _delete = () => {
6946
7559
  if (selection.value.length) {
7560
+ const removed = /* @__PURE__ */ new Set();
7561
+ const collect = (node) => {
7562
+ removed.add(node.id);
7563
+ node.children?.forEach(collect);
7564
+ };
7565
+ selection.value.forEach(collect);
7566
+ const nodeMap = renderEngine.value.nodeMap;
7567
+ const danglingConnections = [];
7568
+ nodeMap?.forEach((node) => {
7569
+ const conn = node.connection;
7570
+ if (!removed.has(node.id) && conn?.isValid?.() && (removed.has(conn.start?.id) || removed.has(conn.end?.id))) danglingConnections.push(node);
7571
+ });
7572
+ danglingConnections.forEach((node) => node.remove());
6947
7573
  selection.value.forEach((node) => {
6948
7574
  node.remove();
6949
7575
  });
@@ -7365,6 +7991,7 @@ var aliases = {
7365
7991
  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
7992
  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
7993
  check: "M21 7L9 19l-5.5-5.5l1.41-1.41L9 16.17L19.59 5.59z",
7994
+ plus: "M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6z",
7368
7995
  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
7996
  frame: "M17 9v6H7V9zm2-6h-2v3h2zM7 3H5v3h2zm16 4h-3v2h3zm-4 0H5v10h14zM4 7H1v2h3zm19 8h-3v2h3zM4 15H1v2h3zm15 3h-2v3h2zM7 18H5v3h2z",
7370
7997
  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",
@@ -7387,7 +8014,11 @@ var aliases = {
7387
8014
  arrow: "M5 17.59L15.59 7H9V5h10v10h-2V8.41L6.41 19z",
7388
8015
  ellipse: "M12 20a8 8 0 0 1-8-8a8 8 0 0 1 8-8a8 8 0 0 1 8 8a8 8 0 0 1-8 8m0-18A10 10 0 0 0 2 12a10 10 0 0 0 10 10a10 10 0 0 0 10-10A10 10 0 0 0 12 2",
7389
8016
  polygon: "M12 2L1 21h22M12 6l7.53 13H4.47",
7390
- star: "m12 15.39l-3.76 2.27l.99-4.28l-3.32-2.88l4.38-.37L12 6.09l1.71 4.04l4.38.37l-3.32 2.88l.99 4.28M22 9.24l-7.19-.61L12 2L9.19 8.63L2 9.24l5.45 4.73L5.82 21L12 17.27L18.18 21l-1.64-7.03z"
8017
+ star: "m12 15.39l-3.76 2.27l.99-4.28l-3.32-2.88l4.38-.37L12 6.09l1.71 4.04l4.38.37l-3.32 2.88l.99 4.28M22 9.24l-7.19-.61L12 2L9.19 8.63L2 9.24l5.45 4.73L5.82 21L12 17.27L18.18 21l-1.64-7.03z",
8018
+ table: "M4,3H20A2,2 0 0,1 22,5V19A2,2 0 0,1 20,21H4A2,2 0 0,1 2,19V5A2,2 0 0,1 4,3M4,7V11H8V7H4M10,7V11H14V7H10M16,7V11H20V7H16M4,13V17H8V13H4M10,13V17H14V13H10M16,13V17H20V13H16Z",
8019
+ chartBar: "M22,21H2V3H4V19H6V10H10V19H12V6H16V19H18V14H22V21Z",
8020
+ chartLine: "M3.5,18.49L9.5,12.48L13.5,16.48L22,6.92L20.59,5.51L13.5,13.47L9.5,9.47L2,16.99L3.5,18.49Z",
8021
+ chartPie: "M11,2V22C5.9,21.5 2,17.2 2,12C2,6.8 5.9,2.5 11,2M13,2V11H22C21.5,6.2 17.8,2.5 13,2M13,13V22C17.7,21.5 21.5,17.8 22,13H13Z"
7391
8022
  };
7392
8023
  var svg = { component: SvgIcon };
7393
8024
  //#endregion
@@ -7882,43 +8513,6 @@ function useOverlay() {
7882
8513
  return item;
7883
8514
  }
7884
8515
  //#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
8516
  //#region src/components/Frame.vue
7923
8517
  var Frame_default = /* @__PURE__ */ defineComponent({
7924
8518
  __name: "Frame",
@@ -7976,7 +8570,7 @@ var Frame_default = /* @__PURE__ */ defineComponent({
7976
8570
  });
7977
8571
  //#endregion
7978
8572
  //#region src/components/Frames.vue?vue&type=script&setup=true&lang.ts
7979
- var _hoisted_1$30 = { class: "m-frames" };
8573
+ var _hoisted_1$31 = { class: "m-frames" };
7980
8574
  //#endregion
7981
8575
  //#region src/components/Frames.vue
7982
8576
  var Frames_default = /* @__PURE__ */ defineComponent({
@@ -7985,7 +8579,7 @@ var Frames_default = /* @__PURE__ */ defineComponent({
7985
8579
  const { frames, getConfigRef } = useEditor();
7986
8580
  const config = getConfigRef("canvas.frame");
7987
8581
  return (_ctx, _cache) => {
7988
- return openBlock(), createElementBlock("div", _hoisted_1$30, [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(frames), (frame, key) => {
8582
+ return openBlock(), createElementBlock("div", _hoisted_1$31, [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(frames), (frame, key) => {
7989
8583
  return openBlock(), createBlock(Frame_default, {
7990
8584
  key,
7991
8585
  "model-value": frame,
@@ -8131,7 +8725,7 @@ var history_default = definePlugin((editor) => {
8131
8725
  });
8132
8726
  //#endregion
8133
8727
  //#region src/components/Hover.vue?vue&type=script&setup=true&lang.ts
8134
- var _hoisted_1$29 = ["data-name"];
8728
+ var _hoisted_1$30 = ["data-name"];
8135
8729
  //#endregion
8136
8730
  //#region src/components/Hover.vue
8137
8731
  var Hover_default = /* @__PURE__ */ defineComponent({
@@ -8150,7 +8744,7 @@ var Hover_default = /* @__PURE__ */ defineComponent({
8150
8744
  borderRadius: `${(unref(hoverElement).style.borderRadius ?? 0) * unref(camera).zoom.x}px`,
8151
8745
  ...hoverElementObb.value.toCssStyle()
8152
8746
  })
8153
- }, null, 12, _hoisted_1$29)) : createCommentVNode("", true);
8747
+ }, null, 12, _hoisted_1$30)) : createCommentVNode("", true);
8154
8748
  };
8155
8749
  }
8156
8750
  });
@@ -8419,10 +9013,10 @@ var Btn_default = /* @__PURE__ */ defineComponent({
8419
9013
  });
8420
9014
  //#endregion
8421
9015
  //#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 = {
9016
+ var _hoisted_1$29 = ["data-id"];
9017
+ var _hoisted_2$15 = { class: "m-layer__content" };
9018
+ var _hoisted_3$14 = { class: "m-layer__prepend" };
9019
+ var _hoisted_4$8 = {
8426
9020
  key: 0,
8427
9021
  class: "m-layer__name"
8428
9022
  };
@@ -8463,6 +9057,13 @@ var Layer_default = /* @__PURE__ */ defineComponent({
8463
9057
  const selected = computed(() => selection.value.some((v) => v.equal(props.node)));
8464
9058
  const children = computed(() => props.node.children);
8465
9059
  const childrenLength = computed(() => children.value.length);
9060
+ const openedShownCount = computed(() => {
9061
+ let n = 0;
9062
+ openedItems.forEach((v) => {
9063
+ if (v.value) n++;
9064
+ });
9065
+ return n;
9066
+ });
8466
9067
  const inputDom = ref();
8467
9068
  const isHoverElement = computed(() => props.node?.equal(hoverElement.value));
8468
9069
  const hovering = ref(false);
@@ -8566,8 +9167,8 @@ var Layer_default = /* @__PURE__ */ defineComponent({
8566
9167
  }, [
8567
9168
  _cache[5] || (_cache[5] = createElementVNode("span", { class: "m-layer__underlay" }, null, -1)),
8568
9169
  _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), {
9170
+ createElementVNode("div", _hoisted_2$15, [
9171
+ createElementVNode("div", _hoisted_3$14, [childrenLength.value ? (openBlock(), createBlock(unref(Icon_default), {
8571
9172
  key: 0,
8572
9173
  class: "m-layer__arrow",
8573
9174
  icon: "$arrowRight",
@@ -8578,7 +9179,7 @@ var Layer_default = /* @__PURE__ */ defineComponent({
8578
9179
  class: "m-layer__thumbnail",
8579
9180
  onDblclick: onDblclickThumbnail
8580
9181
  }, [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", {
9182
+ props.root ? (openBlock(), createElementBlock("div", _hoisted_4$8, toDisplayString(unref(t)("layers")), 1)) : (openBlock(), createElementBlock("div", {
8582
9183
  key: 1,
8583
9184
  class: "m-layer__name",
8584
9185
  onDblclick: onDblclickName
@@ -8599,7 +9200,7 @@ var Layer_default = /* @__PURE__ */ defineComponent({
8599
9200
  createElementVNode("div", { class: normalizeClass(["m-layer__action", {
8600
9201
  "m-layer__action--hover": hovering.value,
8601
9202
  "m-layer__action--show": hovering.value || unref(isLock)(props.node) || !unref(isVisible)(props.node)
8602
- }]) }, [props.root ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [Array.from(unref(openedItems).values()).filter((v) => v.value).length > 1 ? (openBlock(), createBlock(Btn_default, {
9203
+ }]) }, [props.root ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [openedShownCount.value > 1 ? (openBlock(), createBlock(Btn_default, {
8603
9204
  key: 0,
8604
9205
  icon: "",
8605
9206
  class: "m-layer__btn m-layer__btn--show",
@@ -8625,7 +9226,7 @@ var Layer_default = /* @__PURE__ */ defineComponent({
8625
9226
  _: 1
8626
9227
  }, 8, ["class"])], 64))], 2)
8627
9228
  ])
8628
- ], 46, _hoisted_1$28), opened.value ? (openBlock(true), createElementBlock(Fragment, { key: 0 }, renderList(childrenLength.value, (i) => {
9229
+ ], 46, _hoisted_1$29), opened.value ? (openBlock(true), createElementBlock(Fragment, { key: 0 }, renderList(childrenLength.value, (i) => {
8629
9230
  return openBlock(), createBlock(_component_MceLayer, {
8630
9231
  key: i,
8631
9232
  node: children.value[childrenLength.value - i],
@@ -8642,8 +9243,8 @@ var Layer_default = /* @__PURE__ */ defineComponent({
8642
9243
  });
8643
9244
  //#endregion
8644
9245
  //#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" };
9246
+ var _hoisted_1$28 = { class: "m-layers" };
9247
+ var _hoisted_2$14 = { class: "m-layers__wrapper" };
8647
9248
  //#endregion
8648
9249
  //#region src/components/Layers.vue
8649
9250
  var Layers_default = /* @__PURE__ */ defineComponent({
@@ -8677,7 +9278,7 @@ var Layers_default = /* @__PURE__ */ defineComponent({
8677
9278
  layerScrollIntoView();
8678
9279
  });
8679
9280
  return (_ctx, _cache) => {
8680
- return openBlock(), createElementBlock("div", _hoisted_1$27, [createElementVNode("div", _hoisted_2$13, [createVNode(Layer_default, {
9281
+ return openBlock(), createElementBlock("div", _hoisted_1$28, [createElementVNode("div", _hoisted_2$14, [createVNode(Layer_default, {
8681
9282
  root: true,
8682
9283
  node: unref(root),
8683
9284
  opened: true
@@ -8712,13 +9313,13 @@ var _plugin_vue_export_helper_default = (sfc, props) => {
8712
9313
  //#endregion
8713
9314
  //#region src/components/MadeWith.vue
8714
9315
  var _sfc_main = {};
8715
- var _hoisted_1$26 = {
9316
+ var _hoisted_1$27 = {
8716
9317
  class: "m-made-with",
8717
9318
  href: "https://github.com/qq15725/mce",
8718
9319
  target: "_blank"
8719
9320
  };
8720
9321
  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)])]);
9322
+ return openBlock(), createElementBlock("a", _hoisted_1$27, [..._cache[0] || (_cache[0] = [createElementVNode("div", null, "MADE WITH", -1), createElementVNode("div", null, "MCE", -1)])]);
8722
9323
  }
8723
9324
  var MadeWith_default = /* @__PURE__ */ _plugin_vue_export_helper_default(_sfc_main, [["render", _sfc_render]]);
8724
9325
  //#endregion
@@ -8740,7 +9341,7 @@ var madeWith_default = definePlugin((editor) => {
8740
9341
  });
8741
9342
  //#endregion
8742
9343
  //#region src/components/MemoryManager.vue?vue&type=script&setup=true&lang.ts
8743
- var _hoisted_1$25 = { class: "m-manage-memory" };
9344
+ var _hoisted_1$26 = { class: "m-manage-memory" };
8744
9345
  //#endregion
8745
9346
  //#region src/components/MemoryManager.vue
8746
9347
  var MemoryManager_default = /* @__PURE__ */ defineComponent({
@@ -8773,7 +9374,7 @@ var MemoryManager_default = /* @__PURE__ */ defineComponent({
8773
9374
  });
8774
9375
  onBeforeUnmount(() => timer && clearInterval(timer));
8775
9376
  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)]);
9377
+ 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
9378
  };
8778
9379
  }
8779
9380
  });
@@ -8897,18 +9498,18 @@ var Overlay_default = /* @__PURE__ */ defineComponent({
8897
9498
  });
8898
9499
  //#endregion
8899
9500
  //#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 = {
9501
+ var _hoisted_1$25 = ["onMouseenter"];
9502
+ var _hoisted_2$13 = ["onClick"];
9503
+ var _hoisted_3$13 = {
8903
9504
  key: 0,
8904
9505
  class: "m-list-item__checked"
8905
9506
  };
8906
- var _hoisted_4$6 = {
9507
+ var _hoisted_4$7 = {
8907
9508
  key: 1,
8908
9509
  class: "m-list-item__prepend"
8909
9510
  };
8910
- var _hoisted_5$4 = { class: "m-list-item__title" };
8911
- var _hoisted_6$3 = {
9511
+ var _hoisted_5$5 = { class: "m-list-item__title" };
9512
+ var _hoisted_6$4 = {
8912
9513
  key: 2,
8913
9514
  class: "m-list-item__kbd"
8914
9515
  };
@@ -9024,18 +9625,18 @@ var Menu_default = /* @__PURE__ */ defineComponent({
9024
9625
  class: normalizeClass(["m-list-item", [item.disabled && "m-list-item--disabled", opened.value === index && "m-list-item--opened"]]),
9025
9626
  onClick: (e) => onClickItem(item, index, e)
9026
9627
  }, [
9027
- hasPrepend.value ? (openBlock(), createElementBlock("div", _hoisted_3$12, [item.checked ? (openBlock(), createBlock(unref(Icon_default), {
9628
+ hasPrepend.value ? (openBlock(), createElementBlock("div", _hoisted_3$13, [item.checked ? (openBlock(), createBlock(unref(Icon_default), {
9028
9629
  key: 0,
9029
9630
  icon: "$check"
9030
9631
  })) : 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),
9632
+ _ctx.$slots.prepend ? (openBlock(), createElementBlock("div", _hoisted_4$7, [renderSlot(_ctx.$slots, "prepend", { item })])) : createCommentVNode("", true),
9633
+ createElementVNode("div", _hoisted_5$5, [renderSlot(_ctx.$slots, "title", { item }, () => [createTextVNode(toDisplayString(item.key), 1)])]),
9634
+ _ctx.$slots.kbd ? (openBlock(), createElementBlock("div", _hoisted_6$4, [renderSlot(_ctx.$slots, "kbd", { item })])) : createCommentVNode("", true),
9034
9635
  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
9636
  key: 0,
9036
9637
  icon: "$arrowRight"
9037
9638
  })) : createCommentVNode("", true)])) : createCommentVNode("", true)
9038
- ], 10, _hoisted_2$12)], 40, _hoisted_1$24))], 64);
9639
+ ], 10, _hoisted_2$13)], 40, _hoisted_1$25))], 64);
9039
9640
  }), 128)), opened.value > -1 && __props.items?.[opened.value]?.children?.length ? (openBlock(), createBlock(_component_MceMenu, {
9040
9641
  key: 0,
9041
9642
  "open-on-hover": "",
@@ -9183,7 +9784,7 @@ var ContextMenu_default = /* @__PURE__ */ defineComponent({
9183
9784
  //#endregion
9184
9785
  //#region src/plugins/menu.ts
9185
9786
  var menu_default = definePlugin((editor, options) => {
9186
- const { canUndo, canRedo, selection, elementSelection, textSelection, config, exporters, components, isElement, exec } = editor;
9787
+ const { canUndo, canRedo, selection, elementSelection, textSelection, config, exporters, components, isElement, exec, mode } = editor;
9187
9788
  const { customContextMenu } = options;
9188
9789
  const hasSelected = computed(() => selection.value.length > 0);
9189
9790
  const exportMenu = computed(() => ({
@@ -9213,6 +9814,18 @@ var menu_default = definePlugin((editor, options) => {
9213
9814
  children: [...exporters.values()].filter((v) => Boolean(v.copyAs)).map((v) => ({ key: `copyAs:${v.name}` }))
9214
9815
  }));
9215
9816
  const nodeMenu = computed(() => [{ key: "addSubNode" }]);
9817
+ const modeMenu = computed(() => ({
9818
+ key: "mode",
9819
+ children: [{
9820
+ key: "mode:canvas",
9821
+ checked: mode.value === "canvas",
9822
+ handle: () => mode.value = "canvas"
9823
+ }, {
9824
+ key: "mode:workflow",
9825
+ checked: mode.value === "workflow",
9826
+ handle: () => mode.value = "workflow"
9827
+ }]
9828
+ }));
9216
9829
  const editMenus1 = computed(() => [
9217
9830
  {
9218
9831
  key: "copy",
@@ -9521,6 +10134,8 @@ var menu_default = definePlugin((editor, options) => {
9521
10134
  else return [
9522
10135
  { key: "paste" },
9523
10136
  { type: "divider" },
10137
+ modeMenu.value,
10138
+ { type: "divider" },
9524
10139
  ...mainMenu.value,
9525
10140
  { type: "divider" },
9526
10141
  exportMenu.value
@@ -9545,9 +10160,9 @@ var menu_default = definePlugin((editor, options) => {
9545
10160
  });
9546
10161
  //#endregion
9547
10162
  //#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" };
10163
+ var _hoisted_1$24 = { class: "m-creator" };
10164
+ var _hoisted_2$12 = { class: "m-creator__tree" };
10165
+ var _hoisted_3$12 = { class: "m-creator__actions" };
9551
10166
  //#endregion
9552
10167
  //#region src/components/Creator.vue
9553
10168
  var Creator_default = /* @__PURE__ */ defineComponent({
@@ -9618,12 +10233,12 @@ var Creator_default = /* @__PURE__ */ defineComponent({
9618
10233
  })];
9619
10234
  }
9620
10235
  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) => {
10236
+ return openBlock(), createElementBlock("div", _hoisted_1$24, [createElementVNode("div", _hoisted_2$12, [(openBlock(true), createElementBlock(Fragment, null, renderList(tree.value, (node, index) => {
9622
10237
  return openBlock(), createBlock(CreatorNode, {
9623
10238
  key: index,
9624
10239
  node
9625
10240
  }, null, 8, ["node"]);
9626
- }), 128))]), createElementVNode("div", _hoisted_3$11, [createVNode(Btn_default, { onClick: cancel }, {
10241
+ }), 128))]), createElementVNode("div", _hoisted_3$12, [createVNode(Btn_default, { onClick: cancel }, {
9627
10242
  default: withCtx(() => [createTextVNode(toDisplayString(unref(t)("cancel")), 1)]),
9628
10243
  _: 1
9629
10244
  }), createVNode(Btn_default, { onClick: create }, {
@@ -9798,12 +10413,12 @@ var pen_default = definePlugin((editor) => {
9798
10413
  });
9799
10414
  //#endregion
9800
10415
  //#region src/components/shared/Tooltip.vue?vue&type=script&setup=true&lang.ts
9801
- var _hoisted_1$22 = {
10416
+ var _hoisted_1$23 = {
9802
10417
  key: 0,
9803
10418
  class: "m-tooltip__arrow"
9804
10419
  };
9805
- var _hoisted_2$10 = { class: "m-tooltip__content" };
9806
- var _hoisted_3$10 = {
10420
+ var _hoisted_2$11 = { class: "m-tooltip__content" };
10421
+ var _hoisted_3$11 = {
9807
10422
  key: 0,
9808
10423
  class: "m-tooltip__kbd"
9809
10424
  };
@@ -9846,7 +10461,7 @@ var Tooltip_default = /* @__PURE__ */ defineComponent({
9846
10461
  target: props.target,
9847
10462
  attach: props.attach
9848
10463
  }, 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)]),
10464
+ 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
10465
  _: 2
9851
10466
  }, [_ctx.$slots.activator ? {
9852
10467
  name: "activator",
@@ -9869,13 +10484,13 @@ var Tooltip_default = /* @__PURE__ */ defineComponent({
9869
10484
  });
9870
10485
  //#endregion
9871
10486
  //#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 = [
10487
+ var _hoisted_1$22 = ["width", "height"];
10488
+ var _hoisted_2$10 = [
9874
10489
  "onDblclick",
9875
10490
  "onMousedown",
9876
10491
  "onMousemove"
9877
10492
  ];
9878
- var _hoisted_3$9 = { style: {
10493
+ var _hoisted_3$10 = { style: {
9879
10494
  "font-size": "0.75rem",
9880
10495
  "text-wrap": "nowrap"
9881
10496
  } };
@@ -10046,15 +10661,15 @@ var Ruler_default = /* @__PURE__ */ defineComponent({
10046
10661
  canvas,
10047
10662
  () => props.zoom,
10048
10663
  () => props.position,
10049
- () => props.selected,
10664
+ () => props.selected?.left,
10665
+ () => props.selected?.top,
10666
+ () => props.selected?.width,
10667
+ () => props.selected?.height,
10050
10668
  () => borderColor.value,
10051
10669
  () => textColor.value
10052
10670
  ], () => {
10053
10671
  render();
10054
- }, {
10055
- immediate: true,
10056
- deep: true
10057
- });
10672
+ }, { immediate: true });
10058
10673
  const resize = useDebounceFn(() => {
10059
10674
  if (!canvas.value) return;
10060
10675
  const _box = canvas.value.parentElement.getBoundingClientRect();
@@ -10146,7 +10761,7 @@ var Ruler_default = /* @__PURE__ */ defineComponent({
10146
10761
  class: "m-ruler__canvas",
10147
10762
  width: props.size,
10148
10763
  height: props.size
10149
- }, null, 8, _hoisted_1$21)], 16)), [[unref(vResizeObserver), unref(resize)]]),
10764
+ }, null, 8, _hoisted_1$22)], 16)), [[unref(vResizeObserver), unref(resize)]]),
10150
10765
  (openBlock(true), createElementBlock(Fragment, null, renderList(lines.value, (item, index) => {
10151
10766
  return openBlock(), createElementBlock("div", {
10152
10767
  key: index,
@@ -10167,7 +10782,7 @@ var Ruler_default = /* @__PURE__ */ defineComponent({
10167
10782
  onMousedown: ($event) => onReflineMousedown($event, index),
10168
10783
  onMousemove: (e) => updateTip(e, item),
10169
10784
  onMouseleave: onLeave
10170
- }, null, 46, _hoisted_2$9);
10785
+ }, null, 46, _hoisted_2$10);
10171
10786
  }), 128)),
10172
10787
  createVNode(Tooltip_default, {
10173
10788
  "model-value": !!tipText.value,
@@ -10175,7 +10790,7 @@ var Ruler_default = /* @__PURE__ */ defineComponent({
10175
10790
  offset: 24,
10176
10791
  location: props.vertical ? "bottom" : "right"
10177
10792
  }, {
10178
- default: withCtx(() => [createElementVNode("div", _hoisted_3$9, toDisplayString(tipText.value), 1)]),
10793
+ default: withCtx(() => [createElementVNode("div", _hoisted_3$10, toDisplayString(tipText.value), 1)]),
10179
10794
  _: 1
10180
10795
  }, 8, [
10181
10796
  "model-value",
@@ -10188,7 +10803,7 @@ var Ruler_default = /* @__PURE__ */ defineComponent({
10188
10803
  });
10189
10804
  //#endregion
10190
10805
  //#region src/components/Rulers.vue?vue&type=script&setup=true&lang.ts
10191
- var _hoisted_1$20 = { class: "m-rulers" };
10806
+ var _hoisted_1$21 = { class: "m-rulers" };
10192
10807
  //#endregion
10193
10808
  //#region src/components/Rulers.vue
10194
10809
  var Rulers_default = /* @__PURE__ */ defineComponent({
@@ -10203,7 +10818,7 @@ var Rulers_default = /* @__PURE__ */ defineComponent({
10203
10818
  const { getConfigRef, camera, selectionAabbInDrawboard } = useEditor();
10204
10819
  const config = getConfigRef("ui.ruler");
10205
10820
  return (_ctx, _cache) => {
10206
- return openBlock(), createElementBlock("div", _hoisted_1$20, [
10821
+ return openBlock(), createElementBlock("div", _hoisted_1$21, [
10207
10822
  createVNode(Ruler_default, {
10208
10823
  modelValue: refLines.value.x,
10209
10824
  "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => refLines.value.x = $event),
@@ -10317,7 +10932,7 @@ var saveAs_default = definePlugin((editor) => {
10317
10932
  });
10318
10933
  //#endregion
10319
10934
  //#region src/components/shared/Scrollbar.vue?vue&type=script&setup=true&lang.ts
10320
- var _hoisted_1$19 = {
10935
+ var _hoisted_1$20 = {
10321
10936
  ref: "trackTplRef",
10322
10937
  class: "m-scrollbar__track"
10323
10938
  };
@@ -10400,7 +11015,7 @@ var Scrollbar_default = /* @__PURE__ */ defineComponent({
10400
11015
  [props.vertical ? "width" : "height"]: `${props.size}px`,
10401
11016
  [props.vertical ? "top" : "left"]: `${props.offset}px`
10402
11017
  })
10403
- }, [createElementVNode("div", _hoisted_1$19, [createElementVNode("div", {
11018
+ }, [createElementVNode("div", _hoisted_1$20, [createElementVNode("div", {
10404
11019
  ref: "thumbTplRef",
10405
11020
  class: normalizeClass(["m-scrollbar__thumb", { "m-scrollbar__thumb--active": isActive.value }]),
10406
11021
  style: normalizeStyle({
@@ -10416,7 +11031,7 @@ var Scrollbar_default = /* @__PURE__ */ defineComponent({
10416
11031
  });
10417
11032
  //#endregion
10418
11033
  //#region src/components/Scrollbars.vue?vue&type=script&setup=true&lang.ts
10419
- var _hoisted_1$18 = { class: "m-scrollbars" };
11034
+ var _hoisted_1$19 = { class: "m-scrollbars" };
10420
11035
  //#endregion
10421
11036
  //#region src/components/Scrollbars.vue
10422
11037
  var Scrollbars_default = /* @__PURE__ */ defineComponent({
@@ -10429,7 +11044,7 @@ var Scrollbars_default = /* @__PURE__ */ defineComponent({
10429
11044
  const props = __props;
10430
11045
  const { camera, rootAabb } = useEditor();
10431
11046
  return (_ctx, _cache) => {
10432
- return openBlock(), createElementBlock("div", _hoisted_1$18, [createVNode(Scrollbar_default, mergeProps(props, {
11047
+ return openBlock(), createElementBlock("div", _hoisted_1$19, [createVNode(Scrollbar_default, mergeProps(props, {
10433
11048
  modelValue: unref(camera).position.y,
10434
11049
  "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => unref(camera).position.y = $event),
10435
11050
  vertical: "",
@@ -10564,22 +11179,22 @@ var ScrollToSelection_default = /* @__PURE__ */ defineComponent({
10564
11179
  });
10565
11180
  //#endregion
10566
11181
  //#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 = [
11182
+ var _hoisted_1$18 = ["rx", "ry"];
11183
+ var _hoisted_2$9 = { "pointer-events": "none" };
11184
+ var _hoisted_3$9 = [
10570
11185
  "x",
10571
11186
  "y",
10572
11187
  "width",
10573
11188
  "height",
10574
11189
  "aria-label"
10575
11190
  ];
10576
- var _hoisted_4$5 = [
11191
+ var _hoisted_4$6 = [
10577
11192
  "cx",
10578
11193
  "cy",
10579
11194
  "r",
10580
11195
  "aria-label"
10581
11196
  ];
10582
- var _hoisted_5$3 = [
11197
+ var _hoisted_5$4 = [
10583
11198
  "x",
10584
11199
  "y",
10585
11200
  "width",
@@ -10588,7 +11203,7 @@ var _hoisted_5$3 = [
10588
11203
  "rx",
10589
11204
  "ry"
10590
11205
  ];
10591
- var _hoisted_6$2 = ["transform"];
11206
+ var _hoisted_6$3 = ["transform"];
10592
11207
  var _hoisted_7$2 = { "pointer-events": "all" };
10593
11208
  var _hoisted_8$2 = [
10594
11209
  "x",
@@ -11201,9 +11816,9 @@ var Transform_default = /* @__PURE__ */ defineComponent({
11201
11816
  fill: "none",
11202
11817
  rx: model.value.borderRadius,
11203
11818
  ry: model.value.borderRadius
11204
- }, null, 8, _hoisted_1$17),
11819
+ }, null, 8, _hoisted_1$18),
11205
11820
  createVNode(Diagonal),
11206
- createElementVNode("g", _hoisted_2$8, [(openBlock(true), createElementBlock(Fragment, null, renderList(computedHandles.value, (handle, index) => {
11821
+ createElementVNode("g", _hoisted_2$9, [(openBlock(true), createElementBlock(Fragment, null, renderList(computedHandles.value, (handle, index) => {
11207
11822
  return openBlock(), createElementBlock(Fragment, { key: index }, [handle.shape ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [handle.shape === "rect" ? (openBlock(), createElementBlock("rect", {
11208
11823
  key: 0,
11209
11824
  x: handle.x,
@@ -11212,14 +11827,14 @@ var Transform_default = /* @__PURE__ */ defineComponent({
11212
11827
  height: handle.height,
11213
11828
  "aria-label": handle.type,
11214
11829
  class: "m-transform__handle"
11215
- }, null, 8, _hoisted_3$8)) : handle.width === handle.height ? (openBlock(), createElementBlock("circle", {
11830
+ }, null, 8, _hoisted_3$9)) : handle.width === handle.height ? (openBlock(), createElementBlock("circle", {
11216
11831
  key: 1,
11217
11832
  cx: handle.x + handle.width / 2,
11218
11833
  cy: handle.y + handle.width / 2,
11219
11834
  r: handle.width / 2,
11220
11835
  "aria-label": handle.type,
11221
11836
  class: "m-transform__handle"
11222
- }, null, 8, _hoisted_4$5)) : (openBlock(), createElementBlock("rect", {
11837
+ }, null, 8, _hoisted_4$6)) : (openBlock(), createElementBlock("rect", {
11223
11838
  key: 2,
11224
11839
  x: handle.x,
11225
11840
  y: handle.y,
@@ -11229,12 +11844,12 @@ var Transform_default = /* @__PURE__ */ defineComponent({
11229
11844
  rx: handle.width / 4,
11230
11845
  ry: handle.height / 4,
11231
11846
  class: "m-transform__handle"
11232
- }, null, 8, _hoisted_5$3))], 64)) : createCommentVNode("", true)], 64);
11847
+ }, null, 8, _hoisted_5$4))], 64)) : createCommentVNode("", true)], 64);
11233
11848
  }), 128)), __props.rotator ? (openBlock(), createElementBlock("g", {
11234
11849
  key: 0,
11235
11850
  transform: `matrix(1, 0, 0, 1, -32, ${model.value.height}) rotate(270 16 16)`,
11236
11851
  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)]),
11852
+ }, [..._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
11853
  createElementVNode("g", _hoisted_7$2, [(openBlock(true), createElementBlock(Fragment, null, renderList(computedHandles.value, (handle, index) => {
11239
11854
  return openBlock(), createElementBlock("rect", {
11240
11855
  key: index,
@@ -11262,7 +11877,7 @@ var Transform_default = /* @__PURE__ */ defineComponent({
11262
11877
  });
11263
11878
  //#endregion
11264
11879
  //#region src/components/shared/Cropper.vue?vue&type=script&setup=true&lang.ts
11265
- var _hoisted_1$16 = { class: "m-cropper" };
11880
+ var _hoisted_1$17 = { class: "m-cropper" };
11266
11881
  //#endregion
11267
11882
  //#region src/components/shared/Cropper.vue
11268
11883
  var Cropper_default = /* @__PURE__ */ defineComponent({
@@ -11461,7 +12076,7 @@ var Cropper_default = /* @__PURE__ */ defineComponent({
11461
12076
  onBeforeMount(() => emit("start"));
11462
12077
  onBeforeUnmount(() => emit("end"));
11463
12078
  return (_ctx, _cache) => {
11464
- return withDirectives((openBlock(), createElementBlock("div", _hoisted_1$16, [
12079
+ return withDirectives((openBlock(), createElementBlock("div", _hoisted_1$17, [
11465
12080
  createElementVNode("div", {
11466
12081
  class: "m-cropper__source",
11467
12082
  style: normalizeStyle(unref(boundingBoxToStyle)(sourceTransform.value))
@@ -11535,24 +12150,24 @@ var ForegroundCropper_default = /* @__PURE__ */ defineComponent({
11535
12150
  });
11536
12151
  //#endregion
11537
12152
  //#region src/components/PathEditor.vue?vue&type=script&setup=true&lang.ts
11538
- var _hoisted_1$15 = {
12153
+ var _hoisted_1$16 = {
11539
12154
  ref: "svgTpl",
11540
12155
  class: "m-path-editor",
11541
12156
  style: { overflow: "visible" }
11542
12157
  };
11543
- var _hoisted_2$7 = ["d"];
11544
- var _hoisted_3$7 = [
12158
+ var _hoisted_2$8 = ["d"];
12159
+ var _hoisted_3$8 = [
11545
12160
  "x1",
11546
12161
  "y1",
11547
12162
  "x2",
11548
12163
  "y2"
11549
12164
  ];
11550
- var _hoisted_4$4 = [
12165
+ var _hoisted_4$5 = [
11551
12166
  "cx",
11552
12167
  "cy",
11553
12168
  "onPointerdown"
11554
12169
  ];
11555
- var _hoisted_5$2 = [
12170
+ var _hoisted_5$3 = [
11556
12171
  "x",
11557
12172
  "y",
11558
12173
  "onPointerdown",
@@ -12240,12 +12855,12 @@ var PathEditor_default = /* @__PURE__ */ defineComponent({
12240
12855
  onUp();
12241
12856
  });
12242
12857
  return (_ctx, _cache) => {
12243
- return openBlock(), createElementBlock("svg", _hoisted_1$15, [
12858
+ return openBlock(), createElementBlock("svg", _hoisted_1$16, [
12244
12859
  createElementVNode("path", {
12245
12860
  class: "m-path-editor__hit",
12246
12861
  d: screenPath.value,
12247
12862
  onDblclick: onInsert
12248
- }, null, 40, _hoisted_2$7),
12863
+ }, null, 40, _hoisted_2$8),
12249
12864
  (openBlock(true), createElementBlock(Fragment, null, renderList(controls.value, (c, i) => {
12250
12865
  return openBlock(), createElementBlock("line", {
12251
12866
  key: `l${i}`,
@@ -12254,7 +12869,7 @@ var PathEditor_default = /* @__PURE__ */ defineComponent({
12254
12869
  y1: c.ay,
12255
12870
  x2: c.x,
12256
12871
  y2: c.y
12257
- }, null, 8, _hoisted_3$7);
12872
+ }, null, 8, _hoisted_3$8);
12258
12873
  }), 128)),
12259
12874
  (openBlock(true), createElementBlock(Fragment, null, renderList(controls.value, (c, i) => {
12260
12875
  return openBlock(), createElementBlock("circle", {
@@ -12264,7 +12879,7 @@ var PathEditor_default = /* @__PURE__ */ defineComponent({
12264
12879
  cy: c.y,
12265
12880
  r: "4",
12266
12881
  onPointerdown: ($event) => onDown($event, c.pi, c.ci, c.field)
12267
- }, null, 40, _hoisted_4$4);
12882
+ }, null, 40, _hoisted_4$5);
12268
12883
  }), 128)),
12269
12884
  (openBlock(true), createElementBlock(Fragment, null, renderList(anchors.value, (a, i) => {
12270
12885
  return openBlock(), createElementBlock("rect", {
@@ -12276,7 +12891,7 @@ var PathEditor_default = /* @__PURE__ */ defineComponent({
12276
12891
  height: "8",
12277
12892
  onPointerdown: ($event) => onDown($event, a.pi, a.ci, "xy"),
12278
12893
  onDblclick: withModifiers(($event) => toggleSmooth(a.pi, a.ci), ["stop"])
12279
- }, null, 42, _hoisted_5$2);
12894
+ }, null, 42, _hoisted_5$3);
12280
12895
  }), 128))
12281
12896
  ], 512);
12282
12897
  };
@@ -12284,7 +12899,7 @@ var PathEditor_default = /* @__PURE__ */ defineComponent({
12284
12899
  });
12285
12900
  //#endregion
12286
12901
  //#region src/components/Selection.vue?vue&type=script&setup=true&lang.ts
12287
- var _hoisted_1$14 = { class: "m-selection" };
12902
+ var _hoisted_1$15 = { class: "m-selection" };
12288
12903
  //#endregion
12289
12904
  //#region src/components/Selection.vue
12290
12905
  var Selection_default = /* @__PURE__ */ defineComponent({
@@ -12323,19 +12938,29 @@ var Selection_default = /* @__PURE__ */ defineComponent({
12323
12938
  });
12324
12939
  const parentObbStyles = computed(() => {
12325
12940
  if (selection.value.length !== 1) return [];
12326
- const obbs = [];
12941
+ const result = [];
12327
12942
  selection.value[0]?.findAncestor((ancestor) => {
12328
- if (isElement(ancestor)) obbs.push(getObb(ancestor, "drawboard"));
12943
+ if (isElement(ancestor)) {
12944
+ const el = ancestor;
12945
+ result.push({
12946
+ id: el.instanceId,
12947
+ style: getObb(el, "drawboard").toCssStyle()
12948
+ });
12949
+ }
12329
12950
  return false;
12330
12951
  });
12331
- return obbs.map((obb) => obb.toCssStyle());
12952
+ return result;
12332
12953
  });
12333
12954
  const selectionObbStyles = computed(() => {
12334
12955
  if (state.value !== "selecting" && elementSelection.value.length === 1) return [];
12335
12956
  return elementSelection.value.map((el) => {
12957
+ const box = getObb(el, "drawboard");
12336
12958
  return {
12337
- ...getObb(el, "drawboard").toCssStyle(),
12338
- borderRadius: `${(el.style.borderRadius ?? 0) * camera.value.zoom.x}px`
12959
+ id: el.instanceId,
12960
+ style: {
12961
+ ...box.toCssStyle(),
12962
+ borderRadius: `${(el.style.borderRadius ?? 0) * camera.value.zoom.x}px`
12963
+ }
12339
12964
  };
12340
12965
  });
12341
12966
  });
@@ -12351,47 +12976,58 @@ var Selection_default = /* @__PURE__ */ defineComponent({
12351
12976
  emit("selectionTransformEnded", ctx);
12352
12977
  }
12353
12978
  const transformValue = computed(() => exec("getTransform"));
12979
+ const isConnection = computed(() => {
12980
+ return elementSelection.value.length === 1 && Boolean(elementSelection.value[0].connection?.isValid());
12981
+ });
12354
12982
  const movable = computed(() => {
12355
- return state.value !== "typing" && elementSelection.value.every((element) => {
12983
+ return state.value !== "typing" && !isConnection.value && elementSelection.value.every((element) => {
12356
12984
  return !isLock(element) && element.meta.movable !== false && element.meta.transformable !== false;
12357
12985
  });
12358
12986
  });
12359
12987
  const resizable = computed(() => {
12360
- return state.value !== "typing" && elementSelection.value.every((element) => {
12988
+ return state.value !== "typing" && !isConnection.value && elementSelection.value.every((element) => {
12361
12989
  return !isLock(element) && element.meta.resizable !== false && element.meta.transformable !== false;
12362
12990
  });
12363
12991
  });
12364
12992
  const rotatable = computed(() => {
12365
- return state.value !== "typing" && elementSelection.value.every((element) => {
12993
+ return state.value !== "typing" && !isConnection.value && elementSelection.value.every((element) => {
12366
12994
  return !isLock(element) && element.meta.rotatable !== false && element.meta.transformable !== false;
12367
12995
  });
12368
12996
  });
12369
12997
  const roundable = computed(() => {
12370
- if (state.value !== "typing" && elementSelection.value.length === 1) {
12998
+ if (state.value !== "typing" && !isConnection.value && elementSelection.value.length === 1) {
12371
12999
  const element = elementSelection.value[0];
12372
13000
  return hoverElement.value?.equal(element) && !isLock(element) && element.foreground.isValid();
12373
13001
  }
12374
13002
  return false;
12375
13003
  });
12376
13004
  function tip() {
12377
- const obb = elementSelection.value.length === 1 ? elementSelection.value[0].size : selectionObb.value;
13005
+ if (elementSelection.value.length === 1) {
13006
+ const el = elementSelection.value[0];
13007
+ const sw = el.style.width;
13008
+ const sh = el.style.height;
13009
+ const w = typeof sw === "number" ? sw : el.size.width;
13010
+ const h = typeof sh === "number" ? sh : el.size.height;
13011
+ return `${Number(w.toFixed(2))} × ${Number(h.toFixed(2))}`;
13012
+ }
13013
+ const obb = selectionObb.value;
12378
13014
  return `${Number(obb.width.toFixed(2))} × ${Number(obb.height.toFixed(2))}`;
12379
13015
  }
12380
13016
  __expose({ transform });
12381
13017
  return (_ctx, _cache) => {
12382
- return openBlock(), createElementBlock("div", _hoisted_1$14, [
12383
- (openBlock(true), createElementBlock(Fragment, null, renderList(parentObbStyles.value, (style, index) => {
13018
+ return openBlock(), createElementBlock("div", _hoisted_1$15, [
13019
+ (openBlock(true), createElementBlock(Fragment, null, renderList(parentObbStyles.value, (item) => {
12384
13020
  return openBlock(), createElementBlock("div", {
12385
- key: index,
13021
+ key: item.id,
12386
13022
  class: "m-selection__parent",
12387
- style: normalizeStyle(style)
13023
+ style: normalizeStyle(item.style)
12388
13024
  }, null, 4);
12389
13025
  }), 128)),
12390
- unref(state) !== "moving" && unref(state) !== "transforming" ? (openBlock(true), createElementBlock(Fragment, { key: 0 }, renderList(selectionObbStyles.value, (style, index) => {
13026
+ unref(state) !== "moving" && unref(state) !== "transforming" ? (openBlock(true), createElementBlock(Fragment, { key: 0 }, renderList(selectionObbStyles.value, (item) => {
12391
13027
  return openBlock(), createElementBlock("div", {
12392
- key: index,
13028
+ key: item.id,
12393
13029
  class: "m-selection__node",
12394
- style: normalizeStyle(style)
13030
+ style: normalizeStyle(item.style)
12395
13031
  }, null, 4);
12396
13032
  }), 128)) : createCommentVNode("", true),
12397
13033
  unref(state) === "selecting" || unref(state) === "painting" ? (openBlock(), createElementBlock("div", {
@@ -12501,11 +13137,20 @@ var selection_default = definePlugin((editor) => {
12501
13137
  }
12502
13138
  function marqueeSelect(marquee = selectionMarquee.value) {
12503
13139
  const area = new Obb2D(marquee);
13140
+ const obbCache = /* @__PURE__ */ new Map();
13141
+ const obbOf = (node) => {
13142
+ let obb = obbCache.get(node);
13143
+ if (!obb) {
13144
+ obb = getObb(node, "drawboard");
13145
+ obbCache.set(node, obb);
13146
+ }
13147
+ return obb;
13148
+ };
12504
13149
  selection.value = root.value?.children.flatMap((node) => {
12505
- if (isFrameNode(node, true) && !area.contains(getObb(node, "drawboard"))) return node.children;
13150
+ if (isFrameNode(node, true) && !area.contains(obbOf(node))) return node.children;
12506
13151
  return [node];
12507
13152
  }).filter((node) => {
12508
- return "isVisibleInTree" in node && node.isVisibleInTree() && getObb(node, "drawboard").overlap(area) && !isLock(node) && !node.findAncestor((ancestor) => isLock(ancestor));
13153
+ return "isVisibleInTree" in node && node.isVisibleInTree() && obbOf(node).overlap(area) && !isLock(node) && !node.findAncestor((ancestor) => isLock(ancestor));
12509
13154
  }) ?? [];
12510
13155
  }
12511
13156
  function groupSelection(inEditorIs) {
@@ -12831,6 +13476,46 @@ var shape_default = definePlugin((editor) => {
12831
13476
  {
12832
13477
  name: "star",
12833
13478
  handle: createHandle([{ data: "M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.62L12 2L9.19 8.62L2 9.24l5.45 4.73L5.82 21z" }])
13479
+ },
13480
+ {
13481
+ name: "table",
13482
+ handle: (start) => {
13483
+ addElement(createTableElement(), {
13484
+ position: start,
13485
+ active: true
13486
+ });
13487
+ return { end: () => activateTool(void 0) };
13488
+ }
13489
+ },
13490
+ {
13491
+ name: "chartBar",
13492
+ handle: (start) => {
13493
+ addElement(createChartElement("column"), {
13494
+ position: start,
13495
+ active: true
13496
+ });
13497
+ return { end: () => activateTool(void 0) };
13498
+ }
13499
+ },
13500
+ {
13501
+ name: "chartLine",
13502
+ handle: (start) => {
13503
+ addElement(createChartElement("line"), {
13504
+ position: start,
13505
+ active: true
13506
+ });
13507
+ return { end: () => activateTool(void 0) };
13508
+ }
13509
+ },
13510
+ {
13511
+ name: "chartPie",
13512
+ handle: (start) => {
13513
+ addElement(createChartElement("pie"), {
13514
+ position: start,
13515
+ active: true
13516
+ });
13517
+ return { end: () => activateTool(void 0) };
13518
+ }
12834
13519
  }
12835
13520
  ],
12836
13521
  hotkeys: [
@@ -12940,7 +13625,7 @@ var slice_default = definePlugin((editor) => {
12940
13625
  });
12941
13626
  //#endregion
12942
13627
  //#region src/components/SmartGuides.vue?vue&type=script&setup=true&lang.ts
12943
- var _hoisted_1$13 = {
13628
+ var _hoisted_1$14 = {
12944
13629
  key: 0,
12945
13630
  class: "m-smart-guides"
12946
13631
  };
@@ -12952,7 +13637,7 @@ var SmartGuides_default = /* @__PURE__ */ defineComponent({
12952
13637
  setup(__props) {
12953
13638
  const { state } = useEditor();
12954
13639
  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) => {
13640
+ return unref(state) === "transforming" || unref(state) === "moving" ? (openBlock(), createElementBlock("div", _hoisted_1$14, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.snapLines, (item, key) => {
12956
13641
  return openBlock(), createElementBlock("div", {
12957
13642
  key,
12958
13643
  class: normalizeClass(item.class.map((v) => `m-smart-guides__${v}`)),
@@ -13917,7 +14602,7 @@ var smartGuides_default = definePlugin((editor) => {
13917
14602
  if (box) {
13918
14603
  const excluded = new Set(elementSelection.value.map((el) => el.instanceId));
13919
14604
  const { vLines, hLines } = parent.value.children.filter((node) => {
13920
- return !excluded.has(node.instanceId) && isElement(node) && viewportAabb.value.overlap(node.globalAabb);
14605
+ return !excluded.has(node.instanceId) && isElement(node) && !node.connection?.isValid() && viewportAabb.value.overlap(node.globalAabb);
13921
14606
  }).map((node) => createBox(node)).filter(Boolean).reduce((store, box) => {
13922
14607
  [
13923
14608
  box.vt,
@@ -14176,7 +14861,7 @@ function isLeftTopLine(line) {
14176
14861
  }
14177
14862
  //#endregion
14178
14863
  //#region src/components/SmartSelection.vue?vue&type=script&setup=true&lang.ts
14179
- var _hoisted_1$12 = ["onPointerdown"];
14864
+ var _hoisted_1$13 = ["onPointerdown"];
14180
14865
  //#endregion
14181
14866
  //#region src/components/SmartSelection.vue
14182
14867
  var SmartSelection_default = /* @__PURE__ */ defineComponent({
@@ -14585,7 +15270,7 @@ var SmartSelection_default = /* @__PURE__ */ defineComponent({
14585
15270
  }, [createElementVNode("div", {
14586
15271
  class: "m-smart-selection__ring",
14587
15272
  onPointerdown: ($event) => onRingDrag($event, item)
14588
- }, null, 40, _hoisted_1$12)], 6);
15273
+ }, null, 40, _hoisted_1$13)], 6);
14589
15274
  }), 128)), currentTransform.value.width && currentTransform.value.height ? (openBlock(), createBlock(Transform_default, mergeProps({
14590
15275
  key: 0,
14591
15276
  "model-value": currentTransform.value
@@ -14667,13 +15352,13 @@ var state_default = definePlugin((editor) => {
14667
15352
  });
14668
15353
  //#endregion
14669
15354
  //#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 = {
15355
+ var _hoisted_1$12 = { class: "m-progress-indicator" };
15356
+ var _hoisted_2$7 = {
14672
15357
  key: 0,
14673
15358
  class: "m-progress-indicator__status"
14674
15359
  };
14675
- var _hoisted_3$6 = { class: "m-progress-indicator__bar" };
14676
- var _hoisted_4$3 = {
15360
+ var _hoisted_3$7 = { class: "m-progress-indicator__bar" };
15361
+ var _hoisted_4$4 = {
14677
15362
  key: 1,
14678
15363
  class: "m-progress-indicator__bar-indeterminate"
14679
15364
  };
@@ -14692,22 +15377,22 @@ var ProgressIndicator_default = /* @__PURE__ */ _plugin_vue_export_helper_defaul
14692
15377
  setup(__props) {
14693
15378
  const progress = useModel(__props, "modelValue");
14694
15379
  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", {
15380
+ 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
15381
  key: 0,
14697
15382
  class: "m-progress-indicator__bar-fill",
14698
15383
  style: normalizeStyle({ width: `${progress.value * 100}%` })
14699
- }, null, 4)) : (openBlock(), createElementBlock("div", _hoisted_4$3))])]);
15384
+ }, null, 4)) : (openBlock(), createElementBlock("div", _hoisted_4$4))])]);
14700
15385
  };
14701
15386
  }
14702
15387
  }), [["__scopeId", "data-v-cc8ac0cb"]]);
14703
15388
  //#endregion
14704
15389
  //#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" };
15390
+ var _hoisted_1$11 = { class: "m-statusbar" };
15391
+ var _hoisted_2$6 = { class: "m-statusbar__main" };
15392
+ var _hoisted_3$6 = { class: "m-statusbar__item" };
15393
+ var _hoisted_4$3 = { class: "m-statusbar__kbd" };
15394
+ var _hoisted_5$2 = { class: "m-statusbar__kbd" };
15395
+ var _hoisted_6$2 = { class: "m-statusbar__item" };
14711
15396
  var _hoisted_7$1 = { class: "m-statusbar__kbd" };
14712
15397
  var _hoisted_8$1 = { class: "m-statusbar__item" };
14713
15398
  var _hoisted_9$1 = { class: "m-statusbar__item" };
@@ -14731,10 +15416,10 @@ var Statusbar_default = /* @__PURE__ */ _plugin_vue_export_helper_default(/* @__
14731
15416
  setup(__props) {
14732
15417
  const { state, t, getKbd, exporting, exportProgress, selection, isElement } = useEditor();
14733
15418
  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)]),
15419
+ return openBlock(), createElementBlock("div", _hoisted_1$11, [createElementVNode("div", _hoisted_2$6, [unref(state) === "typing" ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
15420
+ 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
15421
  _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)])
15422
+ createElementVNode("div", _hoisted_6$2, [createElementVNode("span", _hoisted_7$1, toDisplayString(unref(getKbd)("Escape")), 1), createElementVNode("span", null, toDisplayString(unref(t)("commitChanges")), 1)])
14738
15423
  ], 64)) : unref(state) === "transforming" || unref(state) === "moving" ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [
14739
15424
  createElementVNode("div", _hoisted_8$1, [createVNode(unref(Icon_default), { icon: "$mouseRightClick" })]),
14740
15425
  _cache[3] || (_cache[3] = createElementVNode("span", null, "\xA0/\xA0", -1)),
@@ -14811,29 +15496,29 @@ var test_default = definePlugin((editor) => {
14811
15496
  });
14812
15497
  //#endregion
14813
15498
  //#region src/components/timeline/Playhead.vue?vue&type=script&setup=true&lang.ts
14814
- var _hoisted_1$9 = { class: "m-payhead" };
15499
+ var _hoisted_1$10 = { class: "m-payhead" };
14815
15500
  //#endregion
14816
15501
  //#region src/components/timeline/Playhead.vue
14817
15502
  var Playhead_default = /* @__PURE__ */ defineComponent({
14818
15503
  __name: "Playhead",
14819
15504
  setup(__props) {
14820
15505
  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)])]);
15506
+ 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
15507
  };
14823
15508
  }
14824
15509
  });
14825
15510
  //#endregion
14826
15511
  //#region src/components/timeline/Segment.vue?vue&type=script&setup=true&lang.ts
14827
- var _hoisted_1$8 = ["onMousedown"];
14828
- var _hoisted_2$4 = {
15512
+ var _hoisted_1$9 = ["onMousedown"];
15513
+ var _hoisted_2$5 = {
14829
15514
  key: 0,
14830
15515
  class: "m-segment__edge m-segment__edge--front"
14831
15516
  };
14832
- var _hoisted_3$4 = {
15517
+ var _hoisted_3$5 = {
14833
15518
  class: "m-segment__node",
14834
15519
  style: { "overflow": "hidden" }
14835
15520
  };
14836
- var _hoisted_4$1 = {
15521
+ var _hoisted_4$2 = {
14837
15522
  key: 1,
14838
15523
  class: "m-segment__edge m-segment__edge--end"
14839
15524
  };
@@ -14998,33 +15683,33 @@ var Segment_default = /* @__PURE__ */ defineComponent({
14998
15683
  class: normalizeClass(["m-segment__block", `m-segment__block--${block.kind}`]),
14999
15684
  style: normalizeStyle(blockStyle(block)),
15000
15685
  onMousedown: ($event) => onBlockDown($event, block)
15001
- }, null, 46, _hoisted_1$8);
15686
+ }, null, 46, _hoisted_1$9);
15002
15687
  }), 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)
15688
+ __props.active ? (openBlock(), createElementBlock("div", _hoisted_2$5)) : createCommentVNode("", true),
15689
+ createElementVNode("span", _hoisted_3$5, toDisplayString(unref(thumbnailName)), 1),
15690
+ __props.active ? (openBlock(), createElementBlock("div", _hoisted_4$2)) : createCommentVNode("", true)
15006
15691
  ], 38);
15007
15692
  };
15008
15693
  }
15009
15694
  });
15010
15695
  //#endregion
15011
15696
  //#region src/components/timeline/Track.vue?vue&type=script&setup=true&lang.ts
15012
- var _hoisted_1$7 = { class: "m-track" };
15697
+ var _hoisted_1$8 = { class: "m-track" };
15013
15698
  //#endregion
15014
15699
  //#region src/components/timeline/Track.vue
15015
15700
  var Track_default = /* @__PURE__ */ defineComponent({
15016
15701
  __name: "Track",
15017
15702
  setup(__props) {
15018
15703
  return (_ctx, _cache) => {
15019
- return openBlock(), createElementBlock("div", _hoisted_1$7, [renderSlot(_ctx.$slots, "default")]);
15704
+ return openBlock(), createElementBlock("div", _hoisted_1$8, [renderSlot(_ctx.$slots, "default")]);
15020
15705
  };
15021
15706
  }
15022
15707
  });
15023
15708
  //#endregion
15024
15709
  //#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 };
15710
+ var _hoisted_1$7 = ["data-id"];
15711
+ var _hoisted_2$4 = { class: "m-trackhead__thumbnail" };
15712
+ var _hoisted_3$4 = { key: 1 };
15028
15713
  //#endregion
15029
15714
  //#region src/components/timeline/Trackhead.vue
15030
15715
  var Trackhead_default = /* @__PURE__ */ defineComponent({
@@ -15115,7 +15800,7 @@ var Trackhead_default = /* @__PURE__ */ defineComponent({
15115
15800
  onMouseenter,
15116
15801
  onMouseleave
15117
15802
  }, [
15118
- createElementVNode("div", _hoisted_2$3, [createVNode(unref(Icon_default), { icon: unref(thumbnailIcon) }, null, 8, ["icon"])]),
15803
+ createElementVNode("div", _hoisted_2$4, [createVNode(unref(Icon_default), { icon: unref(thumbnailIcon) }, null, 8, ["icon"])]),
15119
15804
  createElementVNode("div", {
15120
15805
  class: "m-trackhead__name",
15121
15806
  onDblclick: onDblclickName
@@ -15132,7 +15817,7 @@ var Trackhead_default = /* @__PURE__ */ defineComponent({
15132
15817
  onBlur: onInputBlur,
15133
15818
  onKeydown: onInputKeydown,
15134
15819
  onMousedown: _cache[1] || (_cache[1] = withModifiers(() => {}, ["stop"]))
15135
- }, null, 544)), [[vModelText, editValue.value]]) : (openBlock(), createElementBlock("span", _hoisted_3$3, toDisplayString(unref(thumbnailName)), 1))], 32),
15820
+ }, null, 544)), [[vModelText, editValue.value]]) : (openBlock(), createElementBlock("span", _hoisted_3$4, toDisplayString(unref(thumbnailName)), 1))], 32),
15136
15821
  createElementVNode("div", { class: normalizeClass(["m-trackhead__action", { "m-trackhead__action--show": showActions.value }]) }, [createElementVNode("button", {
15137
15822
  type: "button",
15138
15823
  class: normalizeClass(["m-trackhead__btn", { "m-trackhead__btn--show": unref(isLock)(__props.node) }]),
@@ -15144,18 +15829,18 @@ var Trackhead_default = /* @__PURE__ */ defineComponent({
15144
15829
  onMousedown: _cache[3] || (_cache[3] = withModifiers(() => {}, ["stop"])),
15145
15830
  onClick: onToggleVisible
15146
15831
  }, [createVNode(unref(Icon_default), { icon: unref(isVisible)(__props.node) ? "$visible" : "$unvisible" }, null, 8, ["icon"])], 34)], 2)
15147
- ], 42, _hoisted_1$6);
15832
+ ], 42, _hoisted_1$7);
15148
15833
  };
15149
15834
  }
15150
15835
  });
15151
15836
  //#endregion
15152
15837
  //#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"];
15838
+ var _hoisted_1$6 = { class: "m-timeline__toolbar" };
15839
+ var _hoisted_2$3 = { class: "m-timeline__time" };
15840
+ var _hoisted_3$3 = { class: "m-timeline__time--muted" };
15841
+ var _hoisted_4$1 = { class: "m-timeline__controls" };
15842
+ var _hoisted_5$1 = ["title"];
15843
+ var _hoisted_6$1 = ["title"];
15159
15844
  var _hoisted_7 = ["title"];
15160
15845
  var _hoisted_8 = ["title"];
15161
15846
  var _hoisted_9 = ["title"];
@@ -15253,25 +15938,25 @@ var Timeline_default = /* @__PURE__ */ defineComponent({
15253
15938
  return openBlock(), createElementBlock("div", {
15254
15939
  class: "m-timeline",
15255
15940
  onWheel: _cache[6] || (_cache[6] = withModifiers(() => {}, ["prevent"]))
15256
- }, [createElementVNode("div", _hoisted_1$5, [
15257
- createElementVNode("div", _hoisted_2$2, [
15941
+ }, [createElementVNode("div", _hoisted_1$6, [
15942
+ createElementVNode("div", _hoisted_2$3, [
15258
15943
  createElementVNode("span", null, toDisplayString(currentLabel.value), 1),
15259
15944
  _cache[7] || (_cache[7] = createElementVNode("span", { class: "m-timeline__time-sep" }, "/", -1)),
15260
- createElementVNode("span", _hoisted_3$2, toDisplayString(totalLabel.value), 1)
15945
+ createElementVNode("span", _hoisted_3$3, toDisplayString(totalLabel.value), 1)
15261
15946
  ]),
15262
- createElementVNode("div", _hoisted_4, [
15947
+ createElementVNode("div", _hoisted_4$1, [
15263
15948
  createElementVNode("button", {
15264
15949
  class: "m-timeline__btn",
15265
15950
  type: "button",
15266
15951
  title: unref(t)("seekStart"),
15267
15952
  onClick: _cache[0] || (_cache[0] = ($event) => unref(exec)("seekStart"))
15268
- }, [createVNode(unref(Icon_default), { icon: "$skipPrevious" })], 8, _hoisted_5),
15953
+ }, [createVNode(unref(Icon_default), { icon: "$skipPrevious" })], 8, _hoisted_5$1),
15269
15954
  createElementVNode("button", {
15270
15955
  class: "m-timeline__btn",
15271
15956
  type: "button",
15272
15957
  title: unref(t)("stepBackward"),
15273
15958
  onClick: _cache[1] || (_cache[1] = ($event) => unref(exec)("stepBackward"))
15274
- }, [createVNode(unref(Icon_default), { icon: "$stepBackward" })], 8, _hoisted_6),
15959
+ }, [createVNode(unref(Icon_default), { icon: "$stepBackward" })], 8, _hoisted_6$1),
15275
15960
  createElementVNode("button", {
15276
15961
  class: "m-timeline__btn m-timeline__btn--primary",
15277
15962
  type: "button",
@@ -15511,7 +16196,7 @@ var timeline_default = definePlugin((editor) => {
15511
16196
  });
15512
16197
  //#endregion
15513
16198
  //#region src/components/Drawing.vue?vue&type=script&setup=true&lang.ts
15514
- var _hoisted_1$4 = {
16199
+ var _hoisted_1$5 = {
15515
16200
  key: 0,
15516
16201
  class: "m-drawing__tip"
15517
16202
  };
@@ -15529,7 +16214,7 @@ var Drawing_default = /* @__PURE__ */ defineComponent({
15529
16214
  left: `${unref(drawboardPointer).x}px`,
15530
16215
  top: `${unref(drawboardPointer).y}px`
15531
16216
  })
15532
- }, [unref(activeTool)?.name ? (openBlock(), createElementBlock("div", _hoisted_1$4, toDisplayString(unref(t)(unref(activeTool).name)), 1)) : createCommentVNode("", true)], 4)) : createCommentVNode("", true);
16217
+ }, [unref(activeTool)?.name ? (openBlock(), createElementBlock("div", _hoisted_1$5, toDisplayString(unref(t)(unref(activeTool).name)), 1)) : createCommentVNode("", true)], 4)) : createCommentVNode("", true);
15533
16218
  };
15534
16219
  }
15535
16220
  });
@@ -15552,9 +16237,9 @@ var tool_default = definePlugin((editor) => {
15552
16237
  });
15553
16238
  //#endregion
15554
16239
  //#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 };
16240
+ var _hoisted_1$4 = { class: "m-toolbelt" };
16241
+ var _hoisted_2$2 = { key: 0 };
16242
+ var _hoisted_3$2 = { key: 1 };
15558
16243
  //#endregion
15559
16244
  //#region src/components/Toolbelt.vue
15560
16245
  var Toolbelt_default = /* @__PURE__ */ defineComponent({
@@ -15570,7 +16255,11 @@ var Toolbelt_default = /* @__PURE__ */ defineComponent({
15570
16255
  "arrow",
15571
16256
  "ellipse",
15572
16257
  "polygon",
15573
- "star"
16258
+ "star",
16259
+ "table",
16260
+ "chartBar",
16261
+ "chartLine",
16262
+ "chartPie"
15574
16263
  ].map((key, index) => {
15575
16264
  return {
15576
16265
  key,
@@ -15642,7 +16331,7 @@ var Toolbelt_default = /* @__PURE__ */ defineComponent({
15642
16331
  ];
15643
16332
  });
15644
16333
  return (_ctx, _cache) => {
15645
- return openBlock(), createElementBlock("div", _hoisted_1$3, [(openBlock(true), createElementBlock(Fragment, null, renderList(items.value, (tool, key) => {
16334
+ return openBlock(), createElementBlock("div", _hoisted_1$4, [(openBlock(true), createElementBlock(Fragment, null, renderList(items.value, (tool, key) => {
15646
16335
  return openBlock(), createElementBlock("div", {
15647
16336
  key,
15648
16337
  class: "m-toolbelt__group"
@@ -15660,7 +16349,7 @@ var Toolbelt_default = /* @__PURE__ */ defineComponent({
15660
16349
  _: 2
15661
16350
  }, 1040, ["active", "onClick"])]),
15662
16351
  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)]),
16352
+ 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
16353
  _: 2
15665
16354
  }, 1024), tool.children?.length ? (openBlock(), createBlock(Menu_default, {
15666
16355
  key: 0,
@@ -16078,6 +16767,9 @@ var TextEditor_default = /* @__PURE__ */ defineComponent({
16078
16767
  await nextTick();
16079
16768
  if (editor.pointerDown(e)) {
16080
16769
  editor.selectAll();
16770
+ requestAnimationFrame(() => {
16771
+ if (state.value === "typing") editor.selectAll();
16772
+ });
16081
16773
  return true;
16082
16774
  }
16083
16775
  return false;
@@ -16113,12 +16805,12 @@ var TextEditor_default = /* @__PURE__ */ defineComponent({
16113
16805
  }
16114
16806
  });
16115
16807
  //#endregion
16116
- //#region \0@oxc-project+runtime@0.130.0/helpers/decorateMetadata.js
16808
+ //#region \0@oxc-project+runtime@0.132.0/helpers/decorateMetadata.js
16117
16809
  function __decorateMetadata(k, v) {
16118
16810
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
16119
16811
  }
16120
16812
  //#endregion
16121
- //#region \0@oxc-project+runtime@0.130.0/helpers/decorate.js
16813
+ //#region \0@oxc-project+runtime@0.132.0/helpers/decorate.js
16122
16814
  function __decorate(decorators, target, key, desc) {
16123
16815
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
16124
16816
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -16149,7 +16841,6 @@ function isEqualStyle(style1, style2) {
16149
16841
  const keys = Array.from(new Set([...keys1, ...keys2]));
16150
16842
  return !keys.length || keys.every((key) => style1[key] === style2[key]);
16151
16843
  }
16152
- var emojiRE = /[#*0-9]\uFE0F?\u20E3|[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23ED-\u23EF\u23F1\u23F2\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692\u2694-\u2697\u2699\u269B\u269C\u26A0\u26A7\u26AA\u26B0\u26B1\u26BD\u26BE\u26C4\u26C8\u26CF\u26D1\u26E9\u26F0-\u26F5\u26F7\u26F8\u26FA\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D\u2721\u2733\u2734\u2744\u2747\u2757\u2763\u27A1\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B55\u3030\u303D\u3297\u3299]\uFE0F?|[\u261D\u270C\u270D](?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?|[\u270A\u270B](?:\uD83C[\uDFFB-\uDFFF])?|[\u23E9-\u23EC\u23F0\u23F3\u25FD\u2693\u26A1\u26AB\u26C5\u26CE\u26D4\u26EA\u26FD\u2705\u2728\u274C\u274E\u2753-\u2755\u2795-\u2797\u27B0\u27BF\u2B50]|\u26D3\uFE0F?(?:\u200D\uD83D\uDCA5)?|\u26F9(?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?(?:\u200D[\u2640\u2642]\uFE0F?)?|\u2764\uFE0F?(?:\u200D(?:\uD83D\uDD25|\uD83E\uDE79))?|\uD83C(?:[\uDC04\uDD70\uDD71\uDD7E\uDD7F\uDE02\uDE37\uDF21\uDF24-\uDF2C\uDF36\uDF7D\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F\uDFCD\uDFCE\uDFD4-\uDFDF\uDFF5\uDFF7]\uFE0F?|[\uDF85\uDFC2\uDFC7](?:\uD83C[\uDFFB-\uDFFF])?|[\uDFC4\uDFCA](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDFCB\uDFCC](?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDCCF\uDD8E\uDD91-\uDD9A\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF43\uDF45-\uDF4A\uDF4C-\uDF7C\uDF7E-\uDF84\uDF86-\uDF93\uDFA0-\uDFC1\uDFC5\uDFC6\uDFC8\uDFC9\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF8-\uDFFF]|\uDDE6\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF]|\uDDE7\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF]|\uDDE8\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF7\uDDFA-\uDDFF]|\uDDE9\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF]|\uDDEA\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA]|\uDDEB\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7]|\uDDEC\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE]|\uDDED\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA]|\uDDEE\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9]|\uDDEF\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5]|\uDDF0\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF]|\uDDF1\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE]|\uDDF2\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF]|\uDDF3\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF]|\uDDF4\uD83C\uDDF2|\uDDF5\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE]|\uDDF6\uD83C\uDDE6|\uDDF7\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC]|\uDDF8\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF]|\uDDF9\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF]|\uDDFA\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF]|\uDDFB\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA]|\uDDFC\uD83C[\uDDEB\uDDF8]|\uDDFD\uD83C\uDDF0|\uDDFE\uD83C[\uDDEA\uDDF9]|\uDDFF\uD83C[\uDDE6\uDDF2\uDDFC]|\uDF44(?:\u200D\uD83D\uDFEB)?|\uDF4B(?:\u200D\uD83D\uDFE9)?|\uDFC3(?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D(?:[\u2640\u2642]\uFE0F?(?:\u200D\u27A1\uFE0F?)?|\u27A1\uFE0F?))?|\uDFF3\uFE0F?(?:\u200D(?:\u26A7\uFE0F?|\uD83C\uDF08))?|\uDFF4(?:\u200D\u2620\uFE0F?|\uDB40\uDC67\uDB40\uDC62\uDB40(?:\uDC65\uDB40\uDC6E\uDB40\uDC67|\uDC73\uDB40\uDC63\uDB40\uDC74|\uDC77\uDB40\uDC6C\uDB40\uDC73)\uDB40\uDC7F)?)|\uD83D(?:[\uDC3F\uDCFD\uDD49\uDD4A\uDD6F\uDD70\uDD73\uDD76-\uDD79\uDD87\uDD8A-\uDD8D\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA\uDECB\uDECD-\uDECF\uDEE0-\uDEE5\uDEE9\uDEF0\uDEF3]\uFE0F?|[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC](?:\uD83C[\uDFFB-\uDFFF])?|[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4\uDEB5](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD74\uDD90](?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?|[\uDC00-\uDC07\uDC09-\uDC14\uDC16-\uDC25\uDC27-\uDC3A\uDC3C-\uDC3E\uDC40\uDC44\uDC45\uDC51-\uDC65\uDC6A\uDC79-\uDC7B\uDC7D-\uDC80\uDC84\uDC88-\uDC8E\uDC90\uDC92-\uDCA9\uDCAB-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDDA4\uDDFB-\uDE2D\uDE2F-\uDE34\uDE37-\uDE41\uDE43\uDE44\uDE48-\uDE4A\uDE80-\uDEA2\uDEA4-\uDEB3\uDEB7-\uDEBF\uDEC1-\uDEC5\uDED0-\uDED2\uDED5-\uDED7\uDEDC-\uDEDF\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB\uDFF0]|\uDC08(?:\u200D\u2B1B)?|\uDC15(?:\u200D\uD83E\uDDBA)?|\uDC26(?:\u200D(?:\u2B1B|\uD83D\uDD25))?|\uDC3B(?:\u200D\u2744\uFE0F?)?|\uDC41\uFE0F?(?:\u200D\uD83D\uDDE8\uFE0F?)?|\uDC68(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDC68\uDC69]\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]))|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFC-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFD-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFD\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFE])))?))?|\uDC69(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?[\uDC68\uDC69]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?|\uDC69\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?))|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]))|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFC-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFD-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFD\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFE])))?))?|\uDC6F(?:\u200D[\u2640\u2642]\uFE0F?)?|\uDD75(?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?(?:\u200D[\u2640\u2642]\uFE0F?)?|\uDE2E(?:\u200D\uD83D\uDCA8)?|\uDE35(?:\u200D\uD83D\uDCAB)?|\uDE36(?:\u200D\uD83C\uDF2B\uFE0F?)?|\uDE42(?:\u200D[\u2194\u2195]\uFE0F?)?|\uDEB6(?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D(?:[\u2640\u2642]\uFE0F?(?:\u200D\u27A1\uFE0F?)?|\u27A1\uFE0F?))?)|\uD83E(?:[\uDD0C\uDD0F\uDD18-\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5\uDEC3-\uDEC5\uDEF0\uDEF2-\uDEF8](?:\uD83C[\uDFFB-\uDFFF])?|[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD\uDDCF\uDDD4\uDDD6-\uDDDD](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDDDE\uDDDF](?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD0D\uDD0E\uDD10-\uDD17\uDD20-\uDD25\uDD27-\uDD2F\uDD3A\uDD3F-\uDD45\uDD47-\uDD76\uDD78-\uDDB4\uDDB7\uDDBA\uDDBC-\uDDCC\uDDD0\uDDE0-\uDDFF\uDE70-\uDE7C\uDE80-\uDE89\uDE8F-\uDEC2\uDEC6\uDECE-\uDEDC\uDEDF-\uDEE9]|\uDD3C(?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF])?|\uDDCE(?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D(?:[\u2640\u2642]\uFE0F?(?:\u200D\u27A1\uFE0F?)?|\u27A1\uFE0F?))?|\uDDD1(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83E\uDDD1|\uDDD1\u200D\uD83E\uDDD2(?:\u200D\uD83E\uDDD2)?|\uDDD2(?:\u200D\uD83E\uDDD2)?))|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFC-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFD-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFD\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFE]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?))?|\uDEF1(?:\uD83C(?:\uDFFB(?:\u200D\uD83E\uDEF2\uD83C[\uDFFC-\uDFFF])?|\uDFFC(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB\uDFFD-\uDFFF])?|\uDFFD(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])?|\uDFFE(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB-\uDFFD\uDFFF])?|\uDFFF(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB-\uDFFE])?))?)/g;
16153
16844
  function parseHTML(html) {
16154
16845
  const template = document.createElement("template");
16155
16846
  template.innerHTML = html;
@@ -16416,10 +17107,6 @@ var TextEditor = class extends HTMLElement {
16416
17107
  }
16417
17108
  _getNewContent(content, newString = textContentToString(content), oldString = newString) {
16418
17109
  newString = normalizeCRLF(newString);
16419
- newString = newString.replace(emojiRE, (emoji) => {
16420
- if (Array.from(emoji).length > 1) return "?";
16421
- return emoji;
16422
- });
16423
17110
  oldString = normalizeCRLF(oldString);
16424
17111
  const oldStyles = textContentToCharStyles(content);
16425
17112
  const styles = [];
@@ -16428,8 +17115,10 @@ var TextEditor = class extends HTMLElement {
16428
17115
  let prevOldStyle = {};
16429
17116
  diffChars(oldString, newString).forEach((change) => {
16430
17117
  const chars = Array.from(change.value);
16431
- if (change.removed) oldStyleIndex += chars.length;
16432
- else chars.forEach(() => {
17118
+ if (change.removed) {
17119
+ prevOldStyle = normalizeStyle$1(oldStyles[oldStyleIndex] ?? {});
17120
+ oldStyleIndex += chars.length;
17121
+ } else chars.forEach(() => {
16433
17122
  if (change.added) styles[styleIndex] = { ...prevOldStyle };
16434
17123
  else {
16435
17124
  prevOldStyle = normalizeStyle$1(oldStyles[oldStyleIndex]);
@@ -16486,7 +17175,7 @@ var TextEditor = class extends HTMLElement {
16486
17175
  }
16487
17176
  _onInput() {
16488
17177
  const newText = this._textarea.value;
16489
- this.text.content = this._getNewContent(this.text.content, newText, this._oldText);
17178
+ this.text.content = this._getNewContent(this.text.content, newText, textContentToString(this.text.content));
16490
17179
  this._oldText = newText;
16491
17180
  this.text.update();
16492
17181
  this._emit("update");
@@ -16778,504 +17467,847 @@ __decorate([property({
16778
17467
  fallback: false
16779
17468
  }), __decorateMetadata("design:type", Boolean)], TextEditor.prototype, "_showCursor", void 0);
16780
17469
  //#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
- });
17470
+ //#region src/plugins/typography.ts
17471
+ var typography_default = definePlugin((editor) => {
17472
+ const { isElement, elementSelection, textSelection, fonts, registerConfig, t, addElement, activateTool } = editor;
17473
+ const config = registerConfig("typography", { default: { strategy: "autoHeight" } });
17474
+ const hasTextSelectionRange = computed(() => {
17475
+ return (textSelection.value?.length ?? 0) > 1 && textSelection.value[0] !== textSelection.value[1];
17476
+ });
17477
+ const isTextAllSelected = computed(() => {
17478
+ return textSelection.value?.[0].isFirst && textSelection.value?.[1].isLast && textSelection.value?.[1].isLastSelected;
17479
+ });
17480
+ function textFontSizeToFit(element, scale) {
17481
+ function _handle(element) {
17482
+ if (!scale) {
17483
+ const chars = element.text.base.characters;
17484
+ let pos = 0;
17485
+ let char;
17486
+ chars.forEach((_char) => {
17487
+ const _pos = _char.lineBox.left + _char.lineBox.width;
17488
+ if (_pos > pos) {
17489
+ char = _char;
17490
+ pos = _pos;
17491
+ }
16868
17492
  });
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
- }
17493
+ const style = {};
17494
+ const content = chars.filter((_char) => _char.lineBox.top === char?.lineBox.top).map((char) => {
17495
+ Object.assign(style, { ...char.parent.style }, { ...char.parent.parent.style });
17496
+ return char.content;
17497
+ }).join("");
16897
17498
  const { boundingBox } = measureText({
16898
17499
  fonts,
16899
- style,
16900
- content: element.text.content
17500
+ style: {
17501
+ ...element.style.toJSON(),
17502
+ width: "auto"
17503
+ },
17504
+ content: [{ fragments: [{
17505
+ ...style,
17506
+ content
17507
+ }] }]
16901
17508
  });
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
- }
17509
+ const fontSize = (element.style.fontSize || 12) / 2;
17510
+ scale = (element.style.width ?? 0) / (boundingBox.width + fontSize);
16907
17511
  }
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
- });
17512
+ function _scaleStyle(style) {
17513
+ if (style.fontSize) style.fontSize = style.fontSize * scale;
17514
+ if (style.letterSpacing) style.letterSpacing = style.letterSpacing * scale;
17515
+ }
17516
+ _scaleStyle(element.style);
17517
+ if (element.text?.isValid?.() && Array.isArray(element.text?.content)) element.text.content.forEach((p) => {
17518
+ _scaleStyle(p);
17519
+ p.fragments.forEach((f) => {
17520
+ _scaleStyle(f);
16936
17521
  });
16937
17522
  });
17523
+ element.requestRender();
16938
17524
  }
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];
17525
+ _handle(element);
17526
+ element.findOne((descendant) => {
17527
+ if (isElement(descendant)) _handle(descendant);
17528
+ return false;
17529
+ });
17530
+ }
17531
+ function textToFit(element, strategy = config.value.strategy) {
17532
+ if (strategy === "fixedWidthHeight") return;
17533
+ else if (strategy === "autoFontSize") {
17534
+ textFontSizeToFit(element);
17535
+ return;
17536
+ }
17537
+ function _handle(element) {
17538
+ if (!element.text?.isValid?.() || typeof element.text?.content !== "object") return;
17539
+ const isVertical = element.text.base.isVertical;
17540
+ const style = element.style.toJSON();
17541
+ switch (strategy) {
17542
+ case "autoWidth":
17543
+ if (isVertical) style.height = "auto";
17544
+ else style.width = "auto";
16947
17545
  break;
16948
- default:
16949
- value = el.style[key];
17546
+ case "autoHeight":
17547
+ if (isVertical) style.width = "auto";
17548
+ else style.height = "auto";
16950
17549
  break;
16951
17550
  }
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;
17551
+ const { boundingBox } = measureText({
17552
+ fonts,
17553
+ style,
17554
+ content: element.text.content
17555
+ });
17556
+ if (element.style.width !== boundingBox.width || element.style.height !== boundingBox.height) {
17557
+ element.style.width = boundingBox.width;
17558
+ element.style.height = boundingBox.height;
17559
+ element.requestRender();
17560
+ }
17561
+ }
17562
+ _handle(element);
17563
+ element.findOne((descendant) => {
17564
+ if (isElement(descendant)) _handle(descendant);
17565
+ return false;
17566
+ });
17567
+ }
17568
+ function handleTextSelection([start, end], cb) {
17569
+ let flag = true;
17570
+ elementSelection.value[0]?.text?.content.forEach((p, pIndex, pItems) => {
17571
+ if (!flag) return;
17572
+ p.fragments.forEach((f, fIndex, fItems) => {
17573
+ if (!flag) return;
17574
+ const { content, ...fStyle } = f;
17575
+ Array.from(normalizeCRLF(content)).forEach((c, cIndex, cItems) => {
17576
+ flag = cb({
17577
+ 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)),
17578
+ p,
17579
+ pIndex,
17580
+ pLength: pItems.length,
17581
+ f,
17582
+ fIndex,
17583
+ fStyle,
17584
+ fLength: fItems.length,
17585
+ c,
17586
+ cLength: cItems.length,
17587
+ cIndex
17588
+ });
16960
17589
  });
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];
17590
+ });
17591
+ });
17592
+ }
17593
+ function getTextStyle(key) {
17594
+ const el = elementSelection.value[0];
17595
+ if (!el) return;
17596
+ let value;
17597
+ switch (key) {
17598
+ case "fill":
17599
+ case "outline":
17600
+ value = el.text[key];
17601
+ break;
17602
+ default:
17603
+ value = el.style[key];
17604
+ break;
17605
+ }
17606
+ if (hasTextSelectionRange.value && !isTextAllSelected.value) {
17607
+ const selection = textSelection.value;
17608
+ if (selection && selection[0] && selection[1]) handleTextSelection(selection, ({ selected, fStyle }) => {
17609
+ if (selected && fStyle[key]) {
17610
+ value = fStyle[key];
17611
+ return false;
16970
17612
  }
17613
+ return true;
17614
+ });
17615
+ } else {
17616
+ const content = el.text.content;
17617
+ switch (key) {
17618
+ case "fontSize": return content?.reduce((prev, p) => {
17619
+ return p.fragments.reduce((prev, f) => {
17620
+ return ~~Math.max(prev, f[key] ?? 0);
17621
+ }, prev);
17622
+ }, value) ?? value;
17623
+ default: if (content?.length === 1 && content[0].fragments.length === 1 && content[0].fragments[0][key]) return content[0].fragments[0][key];
16971
17624
  }
16972
- return value;
16973
17625
  }
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) {
17626
+ return value;
17627
+ }
17628
+ function setTextContentByEachFragment(handler) {
17629
+ const el = elementSelection.value[0];
17630
+ if (!el) return;
17631
+ const newContent = [];
17632
+ let newParagraph = { fragments: [] };
17633
+ let newFragment;
17634
+ handleTextSelection(textSelection.value, ({ selected, fIndex, fStyle, fLength, c, cIndex, cLength }) => {
17635
+ if (fIndex === 0 && cIndex === 0) {
17636
+ newParagraph = { fragments: [] };
17637
+ newFragment = void 0;
17638
+ }
17639
+ const style = { ...fStyle };
17640
+ if (selected) handler(style);
17641
+ if (newFragment) {
17642
+ const { content: _, ..._style } = newFragment;
17643
+ if (isEqualObject(style, _style)) newFragment.content += c;
17644
+ else {
17645
+ newParagraph.fragments.push(newFragment);
17646
+ newFragment = {
17647
+ ...style,
17648
+ content: c
17649
+ };
17650
+ }
17651
+ } else newFragment = {
17652
+ ...style,
17653
+ content: c
17654
+ };
17655
+ if (fIndex === fLength - 1 && cIndex === cLength - 1) {
17656
+ if (newFragment) newParagraph.fragments.push(newFragment);
17657
+ if (newParagraph.fragments.length) {
17658
+ newContent.push(newParagraph);
16982
17659
  newParagraph = { fragments: [] };
16983
- newFragment = void 0;
16984
17660
  }
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: [] };
17661
+ }
17662
+ return true;
17663
+ });
17664
+ if (newContent.length) el.text = {
17665
+ ...el.text.toJSON(),
17666
+ content: newContent
17667
+ };
17668
+ }
17669
+ function setTextStyle(key, value) {
17670
+ const el = elementSelection.value[0];
17671
+ if (!el) return;
17672
+ switch (key) {
17673
+ case "writingMode":
17674
+ if (el.style[key] !== value) {
17675
+ const { width, height } = el.style;
17676
+ el.style.width = height;
17677
+ el.style.height = width;
17678
+ el.style[key] = value;
17679
+ }
17680
+ break;
17681
+ default:
17682
+ if (hasTextSelectionRange.value && !isTextAllSelected.value) setTextContentByEachFragment((fragment) => {
17683
+ fragment[key] = value;
17684
+ });
17685
+ else {
17686
+ switch (key) {
17687
+ case "fill":
17688
+ case "outline":
17689
+ el.text[key] = value;
17690
+ break;
17691
+ default:
17692
+ el.style[key] = value;
17693
+ break;
17006
17694
  }
17695
+ el.text.content.forEach((p) => {
17696
+ delete p[key];
17697
+ p.fragments.forEach((f) => {
17698
+ delete f[key];
17699
+ });
17700
+ });
17701
+ el.text = el.text.toJSON();
17007
17702
  }
17008
- return true;
17703
+ el.requestDraw();
17704
+ textToFit(el);
17705
+ break;
17706
+ }
17707
+ }
17708
+ function getTextFill() {
17709
+ const el = elementSelection.value[0];
17710
+ if (!el) return;
17711
+ let fill;
17712
+ if (hasTextSelectionRange.value) {
17713
+ fill = getTextStyle("fill");
17714
+ if (!fill) fill = { color: getTextStyle("color") };
17715
+ }
17716
+ fill = fill ?? el.text.fill ?? { color: el.style.color };
17717
+ return fill;
17718
+ }
17719
+ function setTextFill(value) {
17720
+ const el = elementSelection.value[0];
17721
+ if (!el) return;
17722
+ if (hasTextSelectionRange.value && value?.color) setTextStyle("fill", value);
17723
+ else {
17724
+ el.text.fill = value;
17725
+ if (value?.color) el.style.color = value.color;
17726
+ el.text.content.forEach((p) => {
17727
+ delete p.fill;
17728
+ delete p.color;
17729
+ p.fragments.forEach((f) => {
17730
+ delete f.fill;
17731
+ delete f.color;
17732
+ });
17009
17733
  });
17010
- if (newContent.length) el.text = {
17734
+ el.text = {
17011
17735
  ...el.text.toJSON(),
17012
- content: newContent
17736
+ fill: value
17013
17737
  };
17738
+ el.requestDraw();
17014
17739
  }
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;
17740
+ }
17741
+ const addTextElement = (options = {}) => {
17742
+ const { content = t("doubleClickEditText"), style, ...restOptions } = options;
17743
+ return addElement(createTextElement(content, {
17744
+ fontSize: 64,
17745
+ ...style
17746
+ }, fonts), {
17747
+ sizeToFit: true,
17748
+ active: true,
17749
+ ...restOptions
17750
+ });
17751
+ };
17752
+ Object.assign(editor, {
17753
+ hasTextSelectionRange,
17754
+ isTextAllSelected
17755
+ });
17756
+ return {
17757
+ name: "mce:typography",
17758
+ commands: [
17759
+ {
17760
+ command: "addTextElement",
17761
+ handle: addTextElement
17762
+ },
17763
+ {
17764
+ command: "handleTextSelection",
17765
+ handle: handleTextSelection
17766
+ },
17767
+ {
17768
+ command: "textFontSizeToFit",
17769
+ handle: textFontSizeToFit
17770
+ },
17771
+ {
17772
+ command: "textToFit",
17773
+ handle: textToFit
17774
+ },
17775
+ {
17776
+ command: "setTextStyle",
17777
+ handle: setTextStyle
17778
+ },
17779
+ {
17780
+ command: "getTextStyle",
17781
+ handle: getTextStyle
17782
+ },
17783
+ {
17784
+ command: "getTextFill",
17785
+ handle: getTextFill
17786
+ },
17787
+ {
17788
+ command: "setTextFill",
17789
+ handle: setTextFill
17790
+ },
17791
+ {
17792
+ command: "setTextContentByEachFragment",
17793
+ handle: setTextContentByEachFragment
17052
17794
  }
17795
+ ],
17796
+ hotkeys: [{
17797
+ command: "activateTool:text",
17798
+ key: "T"
17799
+ }],
17800
+ loaders: [{
17801
+ name: "txt",
17802
+ accept: ".txt",
17803
+ test: (source) => {
17804
+ if (source instanceof Blob) {
17805
+ if (source.type.startsWith("text/plain")) return true;
17806
+ }
17807
+ if (source instanceof File) {
17808
+ if (/\.txt$/i.test(source.name)) return true;
17809
+ }
17810
+ return false;
17811
+ },
17812
+ load: async (source) => {
17813
+ return createTextElement(await source.text(), void 0, fonts);
17814
+ }
17815
+ }],
17816
+ tools: [{
17817
+ name: "text",
17818
+ handle: (position) => {
17819
+ addTextElement({ position });
17820
+ activateTool(void 0);
17821
+ }
17822
+ }],
17823
+ components: [{
17824
+ type: "overlay",
17825
+ component: TextEditor_default
17826
+ }],
17827
+ setup: async () => {
17828
+ const { setDefaultFont } = editor;
17829
+ onBeforeMount(() => {
17830
+ TextEditor.register();
17831
+ });
17832
+ const defaultFont = config.value.defaultFont;
17833
+ if (defaultFont) await setDefaultFont(defaultFont);
17053
17834
  }
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") };
17835
+ };
17836
+ });
17837
+ //#endregion
17838
+ //#region src/plugins/url.ts
17839
+ var url_default = definePlugin((editor) => {
17840
+ const { load, http } = editor;
17841
+ return {
17842
+ name: "mce:url",
17843
+ loaders: [{
17844
+ name: "url",
17845
+ test: (source) => {
17846
+ return typeof source === "string";
17847
+ },
17848
+ load: async (url) => {
17849
+ const blob = await http.request({
17850
+ url,
17851
+ responseType: "blob"
17852
+ });
17853
+ const file = new File([blob], url, { type: blob.type });
17854
+ try {
17855
+ return await load(file);
17856
+ } catch (error) {
17857
+ throw new Error(`Failed to load source "${url}", ${error}`);
17858
+ }
17859
+ }
17860
+ }]
17861
+ };
17862
+ });
17863
+ //#endregion
17864
+ //#region src/plugins/view.ts
17865
+ var view_default = definePlugin((editor) => {
17866
+ const { config, components } = editor;
17867
+ const getUiConfig = (name) => {
17868
+ return config.value.ui[name];
17869
+ };
17870
+ const setUiVisible = (name, visible) => {
17871
+ const obj = getUiConfig(name);
17872
+ if (obj && "visible" in obj) if (visible === "toggle") obj.visible = !obj.visible;
17873
+ else obj.visible = visible;
17874
+ };
17875
+ const isPanelVisible = (name) => {
17876
+ return Boolean(components.value.find((c) => c.type === "panel" && c.name === name)?.visible.value);
17877
+ };
17878
+ const setPanelVisible = (name, visible) => {
17879
+ const c = components.value.find((c) => c.type === "panel" && c.name === name);
17880
+ if (c) if (visible === "toggle") c.visible.value = !c.visible.value;
17881
+ else c.visible.value = visible;
17882
+ };
17883
+ return {
17884
+ name: "mce:view",
17885
+ commands: [
17886
+ {
17887
+ command: "getUiConfig",
17888
+ handle: getUiConfig
17889
+ },
17890
+ {
17891
+ command: "isUiVisible",
17892
+ handle: (name) => Boolean(getUiConfig(name)?.visible)
17893
+ },
17894
+ {
17895
+ command: "setUiVisible",
17896
+ handle: setUiVisible
17897
+ },
17898
+ {
17899
+ command: "hideUi",
17900
+ handle: (name) => setUiVisible(name, false)
17901
+ },
17902
+ {
17903
+ command: "showUi",
17904
+ handle: (name) => setUiVisible(name, true)
17905
+ },
17906
+ {
17907
+ command: "toggleUi",
17908
+ handle: (name) => setUiVisible(name, "toggle")
17909
+ },
17910
+ {
17911
+ command: "isPanelVisible",
17912
+ handle: isPanelVisible
17913
+ },
17914
+ {
17915
+ command: "setPanelVisible",
17916
+ handle: setPanelVisible
17917
+ },
17918
+ {
17919
+ command: "hidePanel",
17920
+ handle: (name) => setPanelVisible(name, false)
17921
+ },
17922
+ {
17923
+ command: "showPanel",
17924
+ handle: (name) => setPanelVisible(name, true)
17925
+ },
17926
+ {
17927
+ command: "togglePanel",
17928
+ handle: (name) => setPanelVisible(name, "toggle")
17929
+ }
17930
+ ],
17931
+ hotkeys: [{
17932
+ command: "toggleUi:pixelGrid",
17933
+ key: "Shift+\""
17934
+ }, {
17935
+ command: "toggleUi:ruler",
17936
+ key: "Shift+R"
17937
+ }]
17938
+ };
17939
+ });
17940
+ //#endregion
17941
+ //#region src/utils/workflow.ts
17942
+ var INPUT_PORT = {
17943
+ idx: 0,
17944
+ x: 0,
17945
+ y: .5,
17946
+ ang: Math.PI,
17947
+ kind: "input"
17948
+ };
17949
+ var OUTPUT_PORT = {
17950
+ idx: 1,
17951
+ x: 1,
17952
+ y: .5,
17953
+ ang: 0,
17954
+ kind: "output"
17955
+ };
17956
+ function getWorkflowPorts(el) {
17957
+ const custom = el.shape?.connectionPoints;
17958
+ if (custom?.length) return custom.map((p) => ({
17959
+ ...p,
17960
+ kind: p.x < .5 ? "input" : "output"
17961
+ }));
17962
+ if (el.meta?.inEditorIs?.startsWith("Workflow")) return [INPUT_PORT, OUTPUT_PORT];
17963
+ return [OUTPUT_PORT];
17964
+ }
17965
+ function toConnectionPoints(ports) {
17966
+ return ports.map(({ idx, x, y, ang }) => ({
17967
+ idx,
17968
+ x,
17969
+ y,
17970
+ ang
17971
+ }));
17972
+ }
17973
+ //#endregion
17974
+ //#region src/components/Workflow.vue?vue&type=script&setup=true&lang.ts
17975
+ var _hoisted_1$3 = {
17976
+ key: 0,
17977
+ class: "m-workflow"
17978
+ };
17979
+ var _hoisted_2$1 = {
17980
+ key: 0,
17981
+ class: "m-workflow__preview"
17982
+ };
17983
+ var _hoisted_3$1 = ["d"];
17984
+ var _hoisted_4 = ["onPointerdown"];
17985
+ var _hoisted_5 = ["onClick"];
17986
+ var _hoisted_6 = { class: "m-workflow__menu-kbd" };
17987
+ var PORT_GAP = 16;
17988
+ //#endregion
17989
+ //#region src/components/Workflow.vue
17990
+ var Workflow_default = /* @__PURE__ */ defineComponent({
17991
+ __name: "Workflow",
17992
+ setup(__props) {
17993
+ const { mode, elementSelection, getAabb, camera, drawboardAabb, root, isElement, exec } = useEditor();
17994
+ const NODE_TYPES = [
17995
+ {
17996
+ type: "text",
17997
+ label: "文字生成",
17998
+ kbd: "⇧T"
17999
+ },
18000
+ {
18001
+ type: "image",
18002
+ label: "图片生成",
18003
+ kbd: "⇧I"
18004
+ },
18005
+ {
18006
+ type: "video",
18007
+ label: "视频生成",
18008
+ kbd: "⇧V"
17061
18009
  }
17062
- fill = fill ?? el.text.fill ?? { color: el.style.color };
17063
- return fill;
18010
+ ];
18011
+ function isConnectable(el) {
18012
+ return isElement(el) && !el.connection?.isValid?.();
17064
18013
  }
17065
- function setTextFill(value) {
18014
+ const selectedNode = computed(() => {
18015
+ if (mode.value !== "workflow") return void 0;
17066
18016
  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
18017
+ if (!el || !isConnectable(el) || el.getParent?.()?.id !== root.value?.id) return void 0;
18018
+ return el;
18019
+ });
18020
+ const ports = computed(() => {
18021
+ const el = selectedNode.value;
18022
+ if (!el) return [];
18023
+ const a = getAabb(el, "drawboard");
18024
+ return getWorkflowPorts(el).map((p) => {
18025
+ let dx = p.x - .5;
18026
+ let dy = p.y - .5;
18027
+ const len = Math.hypot(dx, dy) || 1;
18028
+ dx /= len;
18029
+ dy /= len;
18030
+ return {
18031
+ kind: p.kind,
18032
+ idx: p.idx,
18033
+ x: a.left + a.width * p.x + dx * PORT_GAP,
18034
+ y: a.top + a.height * p.y + dy * PORT_GAP
17083
18035
  };
17084
- el.requestDraw();
17085
- }
18036
+ });
18037
+ });
18038
+ const drag = ref();
18039
+ const menu = ref();
18040
+ function toDrawboard(e) {
18041
+ return {
18042
+ x: e.clientX - drawboardAabb.value.left,
18043
+ y: e.clientY - drawboardAabb.value.top
18044
+ };
17086
18045
  }
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
18046
+ function findNodeAt(point, excludeId) {
18047
+ return (root.value?.children ?? []).find((n) => {
18048
+ return isConnectable(n) && n.id !== excludeId && getAabb(n, "drawboard").contains(point);
17096
18049
  });
17097
- };
17098
- Object.assign(editor, {
17099
- hasTextSelectionRange,
17100
- isTextAllSelected
18050
+ }
18051
+ function connect(port, sourceId, otherId, otherPorts) {
18052
+ const need = port.kind === "output" ? "input" : "output";
18053
+ const other = otherPorts.find((p) => p.kind === need);
18054
+ if (!other) return false;
18055
+ if (port.kind === "output") exec("addWorkflowConnection", sourceId, port.idx, otherId, other.idx);
18056
+ else exec("addWorkflowConnection", otherId, other.idx, sourceId, port.idx);
18057
+ return true;
18058
+ }
18059
+ function startConnection(port, e) {
18060
+ e.stopPropagation();
18061
+ e.preventDefault();
18062
+ const el = selectedNode.value;
18063
+ if (!el) return;
18064
+ const sourceId = el.id;
18065
+ const from = {
18066
+ x: port.x,
18067
+ y: port.y
18068
+ };
18069
+ drag.value = {
18070
+ port,
18071
+ from,
18072
+ to: { ...from },
18073
+ sourceId
18074
+ };
18075
+ const onMove = (ev) => {
18076
+ if (drag.value) drag.value = {
18077
+ ...drag.value,
18078
+ to: toDrawboard(ev)
18079
+ };
18080
+ };
18081
+ const onUp = (ev) => {
18082
+ document.removeEventListener("pointermove", onMove);
18083
+ document.removeEventListener("pointerup", onUp);
18084
+ const drop = toDrawboard(ev);
18085
+ const target = findNodeAt(drop, sourceId);
18086
+ if (target) {
18087
+ drag.value = void 0;
18088
+ connect(port, sourceId, target.id, getWorkflowPorts(target));
18089
+ } else menu.value = {
18090
+ port,
18091
+ x: drop.x,
18092
+ y: drop.y,
18093
+ position: camera.value.toGlobal(drop, {
18094
+ x: 0,
18095
+ y: 0
18096
+ }),
18097
+ sourceId
18098
+ };
18099
+ };
18100
+ document.addEventListener("pointermove", onMove);
18101
+ document.addEventListener("pointerup", onUp);
18102
+ }
18103
+ function chooseNodeType(type) {
18104
+ const m = menu.value;
18105
+ menu.value = void 0;
18106
+ drag.value = void 0;
18107
+ if (!m) return;
18108
+ const node = exec("addWorkflowNode", type);
18109
+ const w = node.style.width;
18110
+ const h = node.style.height;
18111
+ node.style.left = m.port.kind === "output" ? m.position.x : m.position.x - w;
18112
+ node.style.top = m.position.y - h / 2;
18113
+ connect(m.port, m.sourceId, node.id, [INPUT_PORT, OUTPUT_PORT]);
18114
+ }
18115
+ function closeMenu() {
18116
+ menu.value = void 0;
18117
+ drag.value = void 0;
18118
+ }
18119
+ const previewPath = computed(() => {
18120
+ const d = drag.value;
18121
+ if (!d) return "";
18122
+ const { from, to } = d;
18123
+ const dx = Math.max(40, Math.abs(to.x - from.x) * .5);
18124
+ return `M ${from.x} ${from.y} C ${from.x + dx} ${from.y} ${to.x - dx} ${to.y} ${to.x} ${to.y}`;
17101
18125
  });
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
17132
- },
17133
- {
17134
- command: "setTextFill",
17135
- handle: setTextFill
17136
- },
17137
- {
17138
- command: "setTextContentByEachFragment",
17139
- handle: setTextContentByEachFragment
17140
- }
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;
17157
- },
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
- }
18126
+ function portStyle(p) {
18127
+ return {
18128
+ left: `${p.x}px`,
18129
+ top: `${p.y}px`
18130
+ };
18131
+ }
18132
+ return (_ctx, _cache) => {
18133
+ return unref(mode) === "workflow" ? (openBlock(), createElementBlock("div", _hoisted_1$3, [
18134
+ drag.value ? (openBlock(), createElementBlock("svg", _hoisted_2$1, [createElementVNode("path", { d: previewPath.value }, null, 8, _hoisted_3$1)])) : createCommentVNode("", true),
18135
+ (openBlock(true), createElementBlock(Fragment, null, renderList(ports.value, (port) => {
18136
+ return openBlock(), createElementBlock("div", {
18137
+ key: `${port.kind}:${port.idx}`,
18138
+ class: "m-workflow__port",
18139
+ style: normalizeStyle(portStyle(port)),
18140
+ onPointerdown: ($event) => startConnection(port, $event)
18141
+ }, [createVNode(unref(Icon_default), { icon: "$plus" })], 44, _hoisted_4);
18142
+ }), 128)),
18143
+ menu.value ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [createElementVNode("div", {
18144
+ class: "m-workflow__backdrop",
18145
+ onPointerdown: closeMenu
18146
+ }, null, 32), createElementVNode("div", {
18147
+ class: "m-workflow__menu",
18148
+ style: normalizeStyle({
18149
+ left: `${menu.value.x}px`,
18150
+ top: `${menu.value.y}px`
18151
+ })
18152
+ }, [_cache[0] || (_cache[0] = createElementVNode("div", { class: "m-workflow__menu-title" }, " 新增节点 ", -1)), (openBlock(), createElementBlock(Fragment, null, renderList(NODE_TYPES, (n) => {
18153
+ return createElementVNode("button", {
18154
+ key: n.type,
18155
+ type: "button",
18156
+ class: "m-workflow__menu-item",
18157
+ onClick: ($event) => chooseNodeType(n.type)
18158
+ }, [createElementVNode("span", null, toDisplayString(n.label), 1), createElementVNode("span", _hoisted_6, toDisplayString(n.kbd), 1)], 8, _hoisted_5);
18159
+ }), 64))], 4)], 64)) : createCommentVNode("", true)
18160
+ ])) : createCommentVNode("", true);
17181
18161
  };
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";
18162
+ }
18163
+ });
18164
+ //#endregion
18165
+ //#region src/plugins/workflow.ts
18166
+ var DEFAULT_NODES = {
18167
+ text: {
18168
+ label: "文字生成",
18169
+ title: "✍️ 双击此处输入文字..",
18170
+ body: ["可以在此输入提示词,比如画面描述、产品卖点、活动主题、场景描述、品牌 slogan 等内容。若暂时没有明确内容,也可先输入关键词或草稿,后续随时修改优化哦!", "也可以在底部输入框输入需求,让 AI 自动完成文字生成。"]
18171
+ },
18172
+ image: {
18173
+ label: "图片生成",
18174
+ title: "🖼️ 双击此处描述画面..",
18175
+ body: ["输入画面描述、风格、主体等内容,让 AI 自动完成图片生成。"]
18176
+ },
18177
+ video: {
18178
+ label: "视频生成",
18179
+ title: "🎬 双击此处描述视频..",
18180
+ body: ["输入分镜、动作、风格等内容,让 AI 自动完成视频生成。"]
18181
+ }
18182
+ };
18183
+ //#endregion
18184
+ //#region src/plugins/index.ts
18185
+ var plugins = [
18186
+ arrange_default,
18187
+ autoNest_default,
18188
+ clipboard_default,
18189
+ doc_default,
18190
+ edit_default,
18191
+ formatPaint_default,
18192
+ frame_default,
18193
+ history_default,
18194
+ hover_default,
18195
+ html_default,
18196
+ image_default,
18197
+ import_default,
18198
+ json_default,
18199
+ layers_default,
18200
+ madeWith_default,
18201
+ memory_default,
18202
+ menu_default,
18203
+ node_default,
18204
+ pen_default,
18205
+ ruler_default,
18206
+ saveAs_default,
18207
+ scroll_default,
18208
+ selection_default,
18209
+ shape_default,
18210
+ slice_default,
18211
+ smartGuides_default,
18212
+ smartSelection_default,
18213
+ state_default,
18214
+ statusbar_default,
18215
+ test_default,
18216
+ timeline_default,
18217
+ tool_default,
18218
+ toolbelt_default,
18219
+ transform_default,
18220
+ typography_default,
18221
+ url_default,
18222
+ view_default,
18223
+ definePlugin((editor, options) => {
18224
+ const { addElement, renderEngine } = editor;
18225
+ function getTemplate(type) {
18226
+ return {
18227
+ ...DEFAULT_NODES[type],
18228
+ ...options.workflowNodes?.[type]
18229
+ };
18230
+ }
18231
+ function buildContent(t) {
18232
+ return [...t.title ? [{ fragments: [{
18233
+ content: t.title,
18234
+ color: "#1f2937",
18235
+ fontWeight: 700
18236
+ }] }] : [], ...(t.body ?? []).map((line) => ({ fragments: [{
18237
+ content: line,
18238
+ color: "#9ca3af"
18239
+ }] }))];
18240
+ }
18241
+ function createWorkflowNode(type) {
18242
+ const t = getTemplate(type);
18243
+ return {
18244
+ name: t.label ?? type,
18245
+ style: {
18246
+ width: 380,
18247
+ height: 280,
18248
+ borderRadius: 20,
18249
+ padding: 28,
18250
+ fontSize: 16,
18251
+ lineHeight: 1.6,
18252
+ backgroundColor: "#ffffff",
18253
+ borderColor: "#ececf0",
18254
+ borderWidth: 1
17191
18255
  },
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
- }
18256
+ text: { content: buildContent(t) },
18257
+ meta: {
18258
+ inPptIs: "Shape",
18259
+ inCanvasIs: "Element2D",
18260
+ inEditorIs: `Workflow${type.charAt(0).toUpperCase()}${type.slice(1)}`
17203
18261
  }
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
- };
17225
- 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)
18262
+ };
18263
+ }
18264
+ function addWorkflowNode(type, position) {
18265
+ return addElement(createWorkflowNode(type), {
18266
+ position,
18267
+ active: true
18268
+ });
18269
+ }
18270
+ function materializePorts(id) {
18271
+ const el = renderEngine.value.nodeMap.get(id);
18272
+ if (el && !el.shape?.connectionPoints?.length) el.shape.connectionPoints = toConnectionPoints(getWorkflowPorts(el));
18273
+ }
18274
+ function addWorkflowConnection(startId, startIdx, endId, endIdx) {
18275
+ materializePorts(startId);
18276
+ materializePorts(endId);
18277
+ return addElement({
18278
+ style: { pointerEvents: "none" },
18279
+ outline: {
18280
+ color: "#94a3b8",
18281
+ width: 2,
18282
+ lineCap: "round",
18283
+ lineJoin: "round"
17263
18284
  },
17264
- {
17265
- command: "showPanel",
17266
- handle: (name) => setPanelVisible(name, true)
18285
+ connection: {
18286
+ start: {
18287
+ id: startId,
18288
+ idx: startIdx
18289
+ },
18290
+ end: {
18291
+ id: endId,
18292
+ idx: endIdx
18293
+ },
18294
+ mode: "curved"
17267
18295
  },
17268
- {
17269
- command: "togglePanel",
17270
- handle: (name) => setPanelVisible(name, "toggle")
17271
- }
17272
- ],
17273
- hotkeys: [{
17274
- command: "toggleUi:pixelGrid",
17275
- key: "Shift+\""
18296
+ meta: { inCanvasIs: "Element2D" }
18297
+ });
18298
+ }
18299
+ return {
18300
+ name: "mce:workflow",
18301
+ commands: [{
18302
+ command: "addWorkflowNode",
18303
+ handle: addWorkflowNode
17276
18304
  }, {
17277
- command: "toggleUi:ruler",
17278
- key: "Shift+R"
18305
+ command: "addWorkflowConnection",
18306
+ handle: addWorkflowConnection
18307
+ }],
18308
+ components: [{
18309
+ type: "overlay",
18310
+ component: Workflow_default
17279
18311
  }]
17280
18312
  };
17281
18313
  }),
@@ -17538,13 +18570,14 @@ var Editor = class Editor extends Observable {
17538
18570
  let result;
17539
18571
  if (typeof plugin === "function") result = plugin(this, options);
17540
18572
  else result = plugin;
17541
- const { name, events, commands = [], hotkeys = [], loaders = [], exporters = [], tools = [], components = [], setup } = result;
18573
+ const { name, events, commands = [], hotkeys = [], loaders = [], exporters = [], tools = [], components = [], messages, setup } = result;
17542
18574
  this.registerCommand(commands);
17543
18575
  this.registerHotkey(hotkeys);
17544
18576
  this.registerLoader(loaders);
17545
18577
  this.registerExporter(exporters);
17546
18578
  this.registerTool(tools);
17547
18579
  this.registerComponent(name, components);
18580
+ if (messages) this.registerMessages(messages);
17548
18581
  if (setup) this.setups.push(setup);
17549
18582
  if (events) for (const k in events) this.on(k, events[k]);
17550
18583
  }
@@ -17840,11 +18873,7 @@ var _hoisted_3 = {
17840
18873
  var EditorLayout_default = /* @__PURE__ */ defineComponent({
17841
18874
  __name: "EditorLayout",
17842
18875
  props: {
17843
- ...makeMceStrategyProps({
17844
- activeStrategy: defaultActiveStrategy,
17845
- doubleclickStrategy: defaultDoubleclickStrategy,
17846
- hoverStrategy: defaultHoverStrategy
17847
- }),
18876
+ ...makeMceStrategyProps(),
17848
18877
  editor: Editor
17849
18878
  },
17850
18879
  setup(__props) {
@@ -17858,6 +18887,9 @@ var EditorLayout_default = /* @__PURE__ */ defineComponent({
17858
18887
  editor.setup();
17859
18888
  provide(IconsSymbol, createIcons());
17860
18889
  const { sortedComponents, componentRefs, isElement, isFrameNode, drawboardDom, renderEngine, camera, hoverElement, state, setCursor, exec, isLock, t, selectionAabbInDrawboard, selectionMarquee, elementSelection, drawboardAabb, screenCenterOffset, activeTool } = editor;
18890
+ const activeStrategy = computed(() => props.activeStrategy ?? editor.activeStrategy);
18891
+ const doubleclickStrategy = computed(() => props.doubleclickStrategy ?? editor.doubleclickStrategy);
18892
+ const hoverStrategy = computed(() => props.hoverStrategy ?? editor.hoverStrategy);
17861
18893
  const overlayContainer = useTemplateRef("overlayContainerTpl");
17862
18894
  const canvas = useTemplateRef("canvasTpl");
17863
18895
  const grabbing = ref(false);
@@ -17871,13 +18903,15 @@ var EditorLayout_default = /* @__PURE__ */ defineComponent({
17871
18903
  renderEngine.value.on("pointermove", onEnginePointerMove);
17872
18904
  renderEngine.value.on("pointerover", onEnginePointerOver);
17873
18905
  });
18906
+ let unbindRenderCanvas;
17874
18907
  onMounted(() => {
17875
- bindRenderCanvas(canvas.value, drawboardDom.value);
18908
+ unbindRenderCanvas = bindRenderCanvas(canvas.value, drawboardDom.value);
17876
18909
  });
17877
18910
  onBeforeUnmount(() => {
17878
18911
  renderEngine.value.off("pointerdown", onEnginePointerDown);
17879
18912
  renderEngine.value.off("pointermove", onEnginePointerMove);
17880
18913
  renderEngine.value.off("pointerover", onEnginePointerOver);
18914
+ unbindRenderCanvas?.();
17881
18915
  });
17882
18916
  function bindRenderCanvas(canvas, eventTarget) {
17883
18917
  function onRendered() {
@@ -17910,7 +18944,7 @@ var EditorLayout_default = /* @__PURE__ */ defineComponent({
17910
18944
  })) cursor = "move";
17911
18945
  else {
17912
18946
  const element = event.target;
17913
- const result = props.hoverStrategy({
18947
+ const result = hoverStrategy.value({
17914
18948
  element,
17915
18949
  event,
17916
18950
  editor
@@ -17953,7 +18987,7 @@ var EditorLayout_default = /* @__PURE__ */ defineComponent({
17953
18987
  });
17954
18988
  if (button === 2) {
17955
18989
  if (!inSelection) {
17956
- const result = props.activeStrategy({
18990
+ const result = activeStrategy.value({
17957
18991
  element,
17958
18992
  event: downEvent,
17959
18993
  editor
@@ -17974,7 +19008,7 @@ var EditorLayout_default = /* @__PURE__ */ defineComponent({
17974
19008
  const _dy = Math.abs(currentPos.y - _lastClickPos.y);
17975
19009
  if (now - _lastClickTime < 300 && _dx < 5 && _dy < 5) {
17976
19010
  _lastClickTime = 0;
17977
- props.doubleclickStrategy({
19011
+ doubleclickStrategy.value({
17978
19012
  event: downEvent,
17979
19013
  editor
17980
19014
  });
@@ -17996,7 +19030,7 @@ var EditorLayout_default = /* @__PURE__ */ defineComponent({
17996
19030
  break;
17997
19031
  }
17998
19032
  function onDrag(event) {
17999
- const result = props.activeStrategy({
19033
+ const result = activeStrategy.value({
18000
19034
  element,
18001
19035
  event,
18002
19036
  editor
@@ -18017,7 +19051,7 @@ var EditorLayout_default = /* @__PURE__ */ defineComponent({
18017
19051
  selected = elementSelection.value;
18018
19052
  }
18019
19053
  function onActivate() {
18020
- const result = props.activeStrategy({
19054
+ const result = activeStrategy.value({
18021
19055
  element,
18022
19056
  event: downEvent,
18023
19057
  editor
@@ -18329,4 +19363,4 @@ var Dialog_default = /* @__PURE__ */ defineComponent({
18329
19363
  }
18330
19364
  });
18331
19365
  //#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 };
19366
+ 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, createChartElement, createFlowNodeElement, createImageElement, createShapeElement, createStickyElement, createTableElement, createTextElement, defineMixin, definePlugin, mixins, plugins, useEditor };