mce 0.20.0 → 0.22.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.css CHANGED
@@ -1686,6 +1686,15 @@
1686
1686
  .m-workflow__menu-item:hover {
1687
1687
  background: #f3f4f6;
1688
1688
  }
1689
+ .m-workflow__menu-item-main {
1690
+ display: flex;
1691
+ align-items: center;
1692
+ gap: 8px;
1693
+ }
1694
+ .m-workflow__menu-item-main .m-icon {
1695
+ font-size: 18px;
1696
+ color: #6b7280;
1697
+ }
1689
1698
  .m-workflow__menu-kbd {
1690
1699
  font-size: 12px;
1691
1700
  color: #9ca3af;
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Aabb2D, Animation, Camera2D, DEG_TO_RAD, DrawboardEffect, Element2D, Engine, IN_BROWSER, IN_MAC_OS, Lottie2D, Node as Node$1, Obb2D, Timeline, TimelineNode, Video2D, assets, clamp, customNodes, render } from "modern-canvas";
2
- import { Fragment, Teleport, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createSlots, createTextVNode, createVNode, defineComponent, effectScope, getCurrentInstance, guardReactiveProps, h, inject, isReactive, isRef, markRaw, mergeModels, mergeProps, nextTick, normalizeClass, normalizeProps, normalizeStyle, onActivated, onBeforeMount, onBeforeUnmount, onDeactivated, onMounted, onScopeDispose, openBlock, provide, reactive, readonly, ref, renderList, renderSlot, resolveComponent, resolveDynamicComponent, shallowRef, toDisplayString, toRef, toValue, unref, useAttrs, useId, useModel, useSlots, useTemplateRef, vModelText, vShow, warn, watch, withCtx, withDirectives, withModifiers } from "vue";
2
+ import { Fragment, Teleport, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createSlots, createTextVNode, createVNode, defineComponent, effectScope, getCurrentInstance, guardReactiveProps, h, inject, isReactive, isRef, markRaw, mergeModels, mergeProps, nextTick, normalizeClass, normalizeProps, normalizeStyle, onActivated, onBeforeMount, onBeforeUnmount, onDeactivated, onMounted, onScopeDispose, openBlock, provide, reactive, readonly, ref, renderList, renderSlot, resolveComponent, resolveDynamicComponent, shallowRef, toDisplayString, toRaw, toRef, toValue, unref, useAttrs, useId, useModel, useSlots, useTemplateRef, vModelText, vShow, warn, watch, withCtx, withDirectives, withModifiers } from "vue";
3
3
  import { isClient, onClickOutside, useDebounceFn, useEventListener, useFileDialog, useImage, useLocalStorage, useResizeObserver } from "@vueuse/core";
4
4
  import { Observable, getObjectValueByPath, idGenerator, isCRLF, isEqualObject, normalizeCRLF, normalizeTextContent, property, setObjectValueByPath, textContentToString } from "modern-idoc";
5
5
  import { Text, measureText } from "modern-text";
@@ -6057,6 +6057,9 @@ var en_default = {
6057
6057
  "collapse": "Collapse",
6058
6058
  "statusbar": "Statusbar",
6059
6059
  "creator": "Create node",
6060
+ "workflow:text": "Text",
6061
+ "workflow:image": "Image",
6062
+ "workflow:video": "Video",
6060
6063
  "memoryManager": "Manage memory",
6061
6064
  "toolbelt": "Toolbelt",
6062
6065
  "msaa": "MSAA",
@@ -6189,6 +6192,9 @@ var zh_Hans_default = {
6189
6192
  "stepForward": "前进一帧",
6190
6193
  "collapse": "折叠",
6191
6194
  "creator": "创建节点",
6195
+ "workflow:text": "文字生成",
6196
+ "workflow:image": "图片生成",
6197
+ "workflow:video": "视频生成",
6192
6198
  "memoryManager": "管理内存",
6193
6199
  "toolbelt": "工具腰带",
6194
6200
  "msaa": "抗锯齿",
@@ -8163,6 +8169,116 @@ var edit_default = definePlugin((editor, options) => {
8163
8169
  };
8164
8170
  });
8165
8171
  //#endregion
8172
+ //#region src/plugins/flexLayout.ts
8173
+ /**
8174
+ * Drag-to-reorder for children of a flex/auto-layout container.
8175
+ *
8176
+ * `transform.ts` skips the absolute move for such a child; here we make it
8177
+ * follow the cursor (a temporary left/top offset over its flow slot), swap
8178
+ * order with its siblings as its centre crosses theirs, and on release drop
8179
+ * the offset so it snaps back into its (new) slot.
8180
+ *
8181
+ * The sibling layout is derived analytically from sizes/gap captured once at
8182
+ * drag start + the current children order (the order array updates
8183
+ * synchronously on `moveChild`, but the rendered transforms only catch up on
8184
+ * the next tick — so reading them back with `getObb` mid-drag is stale and
8185
+ * makes the swap oscillate at the boundary). Structural changes run on the raw
8186
+ * (non-reactive) nodes, else the canvas hands a Proxy to yoga's embind which
8187
+ * throws a Proxy-invariant error and drops the child.
8188
+ */
8189
+ var flexLayout_default = definePlugin((editor) => {
8190
+ const { isElement, elementSelection, getObb } = editor;
8191
+ let drag;
8192
+ function flexParentOf(el) {
8193
+ const parent = el?.getParent();
8194
+ return parent && isElement(parent) && parent.style?.display === "flex" ? parent : void 0;
8195
+ }
8196
+ function elementChildren(parent) {
8197
+ return parent.children.filter((c) => isElement(c));
8198
+ }
8199
+ /** el's slot main-start and the siblings' main-axis centres, for one order. */
8200
+ function layout(d, order) {
8201
+ let pos = d.contentStart;
8202
+ let elStart = pos;
8203
+ const centers = [];
8204
+ for (const c of order) {
8205
+ const s = d.size.get(c.instanceId) ?? 0;
8206
+ if (c.equal(d.el)) elStart = pos;
8207
+ else centers.push(pos + s / 2);
8208
+ pos += s + d.gap;
8209
+ }
8210
+ return {
8211
+ elStart,
8212
+ centers
8213
+ };
8214
+ }
8215
+ function start() {
8216
+ drag = void 0;
8217
+ const el = elementSelection.value[0];
8218
+ if (elementSelection.value.length !== 1 || !el) return;
8219
+ const parent = flexParentOf(el);
8220
+ if (!parent) return;
8221
+ const dir = parent.style.flexDirection ?? "row";
8222
+ const horizontal = dir === "row" || dir === "row-reverse";
8223
+ const children = elementChildren(parent);
8224
+ const main = (o) => horizontal ? o.left : o.top;
8225
+ const mainSize = (o) => horizontal ? o.width : o.height;
8226
+ const size = /* @__PURE__ */ new Map();
8227
+ children.forEach((c) => size.set(c.instanceId, mainSize(getObb(c))));
8228
+ const first = getObb(children[0]);
8229
+ const gap = children[1] ? main(getObb(children[1])) - (main(first) + mainSize(first)) : 0;
8230
+ const elObb = getObb(el);
8231
+ drag = {
8232
+ el,
8233
+ parent,
8234
+ horizontal,
8235
+ reverse: typeof dir === "string" && dir.endsWith("-reverse"),
8236
+ gap,
8237
+ contentStart: main(first),
8238
+ crossSlot: horizontal ? elObb.top : elObb.left,
8239
+ size
8240
+ };
8241
+ }
8242
+ function move(value) {
8243
+ if (!drag) return;
8244
+ const d = drag;
8245
+ const dragMain = d.horizontal ? value.left + value.width / 2 : value.top + value.height / 2;
8246
+ let order = elementChildren(d.parent);
8247
+ let { elStart, centers } = layout(d, order);
8248
+ const before = centers.filter((c) => c < dragMain).length;
8249
+ const index = d.reverse ? centers.length - before : before;
8250
+ if (index !== order.findIndex((c) => c.equal(d.el))) {
8251
+ toRaw(d.parent).moveChild(toRaw(d.el), index);
8252
+ order = elementChildren(d.parent);
8253
+ ({elStart} = layout(d, order));
8254
+ }
8255
+ if (d.horizontal) {
8256
+ d.el.style.left = value.left - elStart;
8257
+ d.el.style.top = value.top - d.crossSlot;
8258
+ } else {
8259
+ d.el.style.top = value.top - elStart;
8260
+ d.el.style.left = value.left - d.crossSlot;
8261
+ }
8262
+ }
8263
+ function end() {
8264
+ if (drag) {
8265
+ drag.el.style.left = 0;
8266
+ drag.el.style.top = 0;
8267
+ drag = void 0;
8268
+ }
8269
+ }
8270
+ return {
8271
+ name: "mce:flexLayout",
8272
+ events: {
8273
+ selectionTransformStarted: start,
8274
+ selectionTransformed: (ctx) => {
8275
+ if (ctx.handle === "move") move(ctx.value);
8276
+ },
8277
+ selectionTransformEnded: end
8278
+ }
8279
+ };
8280
+ });
8281
+ //#endregion
8166
8282
  //#region src/plugins/formatPaint.ts
8167
8283
  var formatPaint_default = definePlugin((editor) => {
8168
8284
  const { elementSelection, exec, state } = editor;
@@ -8776,6 +8892,8 @@ function useNode(nodeRef, editor = useEditor()) {
8776
8892
  const node = nodeRef.value;
8777
8893
  let value = node.name;
8778
8894
  if (!value || value[0] === "@") {
8895
+ const inEditor = node.meta?.inEditorIs;
8896
+ if (typeof inEditor === "string" && inEditor.startsWith("Workflow")) return t(`workflow:${inEditor.slice(8).toLowerCase()}`);
8779
8897
  if (inEditorIs(node, "Frame")) return t("frame");
8780
8898
  else if (node.children.filter(isElement).length) value = t("group");
8781
8899
  else if (node instanceof Lottie2D) value = t("lottie");
@@ -9850,7 +9968,7 @@ var _hoisted_6$5 = {
9850
9968
  key: 2,
9851
9969
  class: "m-list-item__kbd"
9852
9970
  };
9853
- var _hoisted_7$4 = {
9971
+ var _hoisted_7$5 = {
9854
9972
  key: 3,
9855
9973
  class: "m-list-item__append"
9856
9974
  };
@@ -9969,7 +10087,7 @@ var Menu_default = /* @__PURE__ */ defineComponent({
9969
10087
  _ctx.$slots.prepend ? (openBlock(), createElementBlock("div", _hoisted_4$8, [renderSlot(_ctx.$slots, "prepend", { item })])) : createCommentVNode("", true),
9970
10088
  createElementVNode("div", _hoisted_5$6, [renderSlot(_ctx.$slots, "title", { item }, () => [createTextVNode(toDisplayString(item.key), 1)])]),
9971
10089
  _ctx.$slots.kbd ? (openBlock(), createElementBlock("div", _hoisted_6$5, [renderSlot(_ctx.$slots, "kbd", { item })])) : createCommentVNode("", true),
9972
- item.children?.length || _ctx.$slots.append ? (openBlock(), createElementBlock("div", _hoisted_7$4, [renderSlot(_ctx.$slots, "append", { item }), item.children?.length ? (openBlock(), createBlock(unref(Icon_default), {
10090
+ item.children?.length || _ctx.$slots.append ? (openBlock(), createElementBlock("div", _hoisted_7$5, [renderSlot(_ctx.$slots, "append", { item }), item.children?.length ? (openBlock(), createBlock(unref(Icon_default), {
9973
10091
  key: 0,
9974
10092
  icon: "$arrowRight"
9975
10093
  })) : createCommentVNode("", true)])) : createCommentVNode("", true)
@@ -11541,8 +11659,8 @@ var _hoisted_5$5 = [
11541
11659
  "ry"
11542
11660
  ];
11543
11661
  var _hoisted_6$4 = ["transform"];
11544
- var _hoisted_7$3 = { "pointer-events": "all" };
11545
- var _hoisted_8$3 = [
11662
+ var _hoisted_7$4 = { "pointer-events": "all" };
11663
+ var _hoisted_8$4 = [
11546
11664
  "x",
11547
11665
  "y",
11548
11666
  "width",
@@ -12187,7 +12305,7 @@ var Transform_default = /* @__PURE__ */ defineComponent({
12187
12305
  transform: `matrix(1, 0, 0, 1, -32, ${model.value.height}) rotate(270 16 16)`,
12188
12306
  class: "m-transform__rotator"
12189
12307
  }, [..._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$4)) : createCommentVNode("", true)]),
12190
- createElementVNode("g", _hoisted_7$3, [(openBlock(true), createElementBlock(Fragment, null, renderList(computedHandles.value, (handle, index) => {
12308
+ createElementVNode("g", _hoisted_7$4, [(openBlock(true), createElementBlock(Fragment, null, renderList(computedHandles.value, (handle, index) => {
12191
12309
  return openBlock(), createElementBlock("rect", {
12192
12310
  key: index,
12193
12311
  ref_for: true,
@@ -12201,7 +12319,7 @@ var Transform_default = /* @__PURE__ */ defineComponent({
12201
12319
  class: "m-transform__handle-rect",
12202
12320
  cursor: transforming.value ? "auto" : getCursor(handle.type),
12203
12321
  onPointerdown: (event) => onPointerDown(event, index)
12204
- }, null, 40, _hoisted_8$3);
12322
+ }, null, 40, _hoisted_8$4);
12205
12323
  }), 128))]),
12206
12324
  createElementVNode("g", _hoisted_9$3, [renderSlot(_ctx.$slots, "svg", { box: model.value })])
12207
12325
  ], 4)),
@@ -13691,7 +13809,7 @@ var selection_default = definePlugin((editor) => {
13691
13809
  selectionTransformed: () => {
13692
13810
  elementSelection.value.forEach((el) => {
13693
13811
  el.findAncestor((ancestor) => {
13694
- if (isElement(ancestor) && !inEditorIs(ancestor, "Frame")) obbToFit(ancestor);
13812
+ if (isElement(ancestor) && !inEditorIs(ancestor, "Frame") && ancestor.style.display !== "flex") obbToFit(ancestor);
13695
13813
  return false;
13696
13814
  });
13697
13815
  });
@@ -15481,6 +15599,16 @@ var SmartSelection_default = /* @__PURE__ */ defineComponent({
15481
15599
  switch (direction) {
15482
15600
  case "horizontal":
15483
15601
  if (center.x < min) {
15602
+ if (prev) {
15603
+ let left = elAabb.right - prev.globalAabb.width;
15604
+ elAabb.x = prev.globalAabb.left;
15605
+ const parentAabb = prev.getParent()?.globalAabb;
15606
+ if (parentAabb) left -= parentAabb.x;
15607
+ prev.style.left = left;
15608
+ prev.updateGlobalTransform();
15609
+ update();
15610
+ }
15611
+ } else if (center.x > max) {
15484
15612
  if (next) {
15485
15613
  const left = next.globalAabb.right - elAabb.width;
15486
15614
  let _left = elAabb.left;
@@ -15491,16 +15619,6 @@ var SmartSelection_default = /* @__PURE__ */ defineComponent({
15491
15619
  next.updateGlobalTransform();
15492
15620
  update();
15493
15621
  }
15494
- } else if (center.x > max) {
15495
- if (prev) {
15496
- let left = elAabb.right - prev.globalAabb.width;
15497
- elAabb.x = prev.globalAabb.left;
15498
- const parentAabb = prev.getParent()?.globalAabb;
15499
- if (parentAabb) left -= parentAabb.x;
15500
- prev.style.left = left;
15501
- prev.updateGlobalTransform();
15502
- update();
15503
- }
15504
15622
  }
15505
15623
  break;
15506
15624
  case "vertical":
@@ -15730,8 +15848,8 @@ var _hoisted_3$7 = { class: "m-statusbar__item" };
15730
15848
  var _hoisted_4$4 = { class: "m-statusbar__kbd" };
15731
15849
  var _hoisted_5$3 = { class: "m-statusbar__kbd" };
15732
15850
  var _hoisted_6$3 = { class: "m-statusbar__item" };
15733
- var _hoisted_7$2 = { class: "m-statusbar__kbd" };
15734
- var _hoisted_8$2 = { class: "m-statusbar__item" };
15851
+ var _hoisted_7$3 = { class: "m-statusbar__kbd" };
15852
+ var _hoisted_8$3 = { class: "m-statusbar__item" };
15735
15853
  var _hoisted_9$2 = { class: "m-statusbar__item" };
15736
15854
  var _hoisted_10$1 = { class: "m-statusbar__kbd" };
15737
15855
  var _hoisted_11$1 = { class: "m-statusbar__item" };
@@ -15756,9 +15874,9 @@ var Statusbar_default = /* @__PURE__ */ _plugin_vue_export_helper_default(/* @__
15756
15874
  return openBlock(), createElementBlock("div", _hoisted_1$12, [createElementVNode("div", _hoisted_2$7, [unref(state) === "typing" ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
15757
15875
  createElementVNode("div", _hoisted_3$7, [createElementVNode("span", _hoisted_4$4, toDisplayString(unref(getKbd)("Command")), 1), createElementVNode("span", _hoisted_5$3, toDisplayString(unref(getKbd)("Enter")), 1)]),
15758
15876
  _cache[1] || (_cache[1] = createElementVNode("span", null, "/", -1)),
15759
- createElementVNode("div", _hoisted_6$3, [createElementVNode("span", _hoisted_7$2, toDisplayString(unref(getKbd)("Escape")), 1), createElementVNode("span", null, toDisplayString(unref(t)("commitChanges")), 1)])
15877
+ createElementVNode("div", _hoisted_6$3, [createElementVNode("span", _hoisted_7$3, toDisplayString(unref(getKbd)("Escape")), 1), createElementVNode("span", null, toDisplayString(unref(t)("commitChanges")), 1)])
15760
15878
  ], 64)) : unref(state) === "transforming" || unref(state) === "moving" ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [
15761
- createElementVNode("div", _hoisted_8$2, [createVNode(unref(Icon_default), { icon: "$mouseRightClick" })]),
15879
+ createElementVNode("div", _hoisted_8$3, [createVNode(unref(Icon_default), { icon: "$mouseRightClick" })]),
15762
15880
  _cache[3] || (_cache[3] = createElementVNode("span", null, "\xA0/\xA0", -1)),
15763
15881
  createElementVNode("div", _hoisted_9$2, [createElementVNode("span", _hoisted_10$1, toDisplayString(unref(getKbd)("Escape")), 1), createElementVNode("span", null, toDisplayString(unref(t)("cancel")), 1)]),
15764
15882
  unref(state) === "moving" ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [_cache[2] || (_cache[2] = createElementVNode("div", { class: "m-statusbar__divider" }, null, -1)), createElementVNode("div", _hoisted_11$1, [createElementVNode("span", _hoisted_12$1, toDisplayString(unref(getKbd)("Shift")), 1), createElementVNode("span", null, toDisplayString(unref(t)("constrainMovement")), 1)])], 64)) : createCommentVNode("", true)
@@ -16472,13 +16590,13 @@ var _hoisted_3$6 = ["onPointerdown"];
16472
16590
  var _hoisted_4$3 = ["onPointerdown"];
16473
16591
  var _hoisted_5$2 = ["onPointerdown"];
16474
16592
  var _hoisted_6$2 = ["onPointerdown"];
16475
- var _hoisted_7$1 = [
16593
+ var _hoisted_7$2 = [
16476
16594
  "onPointerdown",
16477
16595
  "onPointerenter",
16478
16596
  "onDblclick",
16479
16597
  "onContextmenu"
16480
16598
  ];
16481
- var _hoisted_8$1 = ["disabled"];
16599
+ var _hoisted_8$2 = ["disabled"];
16482
16600
  var _hoisted_9$1 = ["disabled"];
16483
16601
  var COL_H = 22;
16484
16602
  var ROW_W = 28;
@@ -17158,7 +17276,7 @@ var TableEditor_default = /* @__PURE__ */ defineComponent({
17158
17276
  onPointerenter: ($event) => onCellPointerenter(cell),
17159
17277
  onDblclick: ($event) => onCellDblclick($event, cell),
17160
17278
  onContextmenu: ($event) => onCellContextmenu($event, cell)
17161
- }, null, 44, _hoisted_7$1);
17279
+ }, null, 44, _hoisted_7$2);
17162
17280
  }), 128)),
17163
17281
  createElementVNode("div", {
17164
17282
  class: normalizeClass(["m-table-editor__selection", { "m-table-editor__selection--range": !isSingleSelection.value }]),
@@ -17213,7 +17331,7 @@ var TableEditor_default = /* @__PURE__ */ defineComponent({
17213
17331
  class: "m-table-editor__menu-item",
17214
17332
  disabled: isSingleSelection.value,
17215
17333
  onClick: _cache[9] || (_cache[9] = ($event) => doMerge())
17216
- }, toDisplayString(unref(t)("table:mergeCells")), 9, _hoisted_8$1),
17334
+ }, toDisplayString(unref(t)("table:mergeCells")), 9, _hoisted_8$2),
17217
17335
  createElementVNode("button", {
17218
17336
  class: "m-table-editor__menu-item",
17219
17337
  disabled: !selectedAnchorMerged.value,
@@ -17633,8 +17751,8 @@ var _hoisted_3$3 = { class: "m-timeline__time--muted" };
17633
17751
  var _hoisted_4$1 = { class: "m-timeline__controls" };
17634
17752
  var _hoisted_5$1 = ["title"];
17635
17753
  var _hoisted_6$1 = ["title"];
17636
- var _hoisted_7 = ["title"];
17637
- var _hoisted_8 = ["title"];
17754
+ var _hoisted_7$1 = ["title"];
17755
+ var _hoisted_8$1 = ["title"];
17638
17756
  var _hoisted_9 = ["title"];
17639
17757
  var _hoisted_10 = ["title"];
17640
17758
  var _hoisted_11 = { class: "m-timeline__main" };
@@ -17754,13 +17872,13 @@ var Timeline_default = /* @__PURE__ */ defineComponent({
17754
17872
  type: "button",
17755
17873
  title: unref(paused) ? unref(t)("play") : unref(t)("pause"),
17756
17874
  onClick: _cache[2] || (_cache[2] = ($event) => unref(exec)("togglePlay"))
17757
- }, [createVNode(unref(Icon_default), { icon: unref(paused) ? "$play" : "$pause" }, null, 8, ["icon"])], 8, _hoisted_7),
17875
+ }, [createVNode(unref(Icon_default), { icon: unref(paused) ? "$play" : "$pause" }, null, 8, ["icon"])], 8, _hoisted_7$1),
17758
17876
  createElementVNode("button", {
17759
17877
  class: "m-timeline__btn",
17760
17878
  type: "button",
17761
17879
  title: unref(t)("stepForward"),
17762
17880
  onClick: _cache[3] || (_cache[3] = ($event) => unref(exec)("stepForward"))
17763
- }, [createVNode(unref(Icon_default), { icon: "$stepForward" })], 8, _hoisted_8),
17881
+ }, [createVNode(unref(Icon_default), { icon: "$stepForward" })], 8, _hoisted_8$1),
17764
17882
  createElementVNode("button", {
17765
17883
  class: "m-timeline__btn",
17766
17884
  type: "button",
@@ -18257,6 +18375,10 @@ var transform_default = definePlugin((editor) => {
18257
18375
  };
18258
18376
  const els = elementSelection.value;
18259
18377
  const isMultiple = els.length > 1;
18378
+ if (type === "move" && els.length === 1) {
18379
+ const parent = els[0].getParent();
18380
+ if (parent && parent.style?.display === "flex") return;
18381
+ }
18260
18382
  if (type === "move") {
18261
18383
  transform.left = Math.round(transform.left);
18262
18384
  transform.top = Math.round(transform.top);
@@ -19113,29 +19235,31 @@ var _hoisted_2$1 = {
19113
19235
  };
19114
19236
  var _hoisted_3$1 = ["d"];
19115
19237
  var _hoisted_4 = ["onPointerdown"];
19116
- var _hoisted_5 = ["onClick"];
19117
- var _hoisted_6 = { class: "m-workflow__menu-kbd" };
19238
+ var _hoisted_5 = { class: "m-workflow__menu-title" };
19239
+ var _hoisted_6 = ["onClick"];
19240
+ var _hoisted_7 = { class: "m-workflow__menu-item-main" };
19241
+ var _hoisted_8 = { class: "m-workflow__menu-kbd" };
19118
19242
  var PORT_GAP = 16;
19119
19243
  //#endregion
19120
19244
  //#region src/components/Workflow.vue
19121
19245
  var Workflow_default = /* @__PURE__ */ defineComponent({
19122
19246
  __name: "Workflow",
19123
19247
  setup(__props) {
19124
- const { mode, elementSelection, getAabb, camera, drawboardAabb, root, isElement, exec } = useEditor();
19248
+ const { mode, elementSelection, getAabb, camera, drawboardAabb, root, isElement, exec, t } = useEditor();
19125
19249
  const NODE_TYPES = [
19126
19250
  {
19127
19251
  type: "text",
19128
- label: "文字生成",
19252
+ icon: "$text",
19129
19253
  kbd: "⇧T"
19130
19254
  },
19131
19255
  {
19132
19256
  type: "image",
19133
- label: "图片生成",
19257
+ icon: "$image",
19134
19258
  kbd: "⇧I"
19135
19259
  },
19136
19260
  {
19137
19261
  type: "video",
19138
- label: "视频生成",
19262
+ icon: "$video",
19139
19263
  kbd: "⇧V"
19140
19264
  }
19141
19265
  ];
@@ -19280,13 +19404,13 @@ var Workflow_default = /* @__PURE__ */ defineComponent({
19280
19404
  left: `${menu.value.x}px`,
19281
19405
  top: `${menu.value.y}px`
19282
19406
  })
19283
- }, [_cache[0] || (_cache[0] = createElementVNode("div", { class: "m-workflow__menu-title" }, " 新增节点 ", -1)), (openBlock(), createElementBlock(Fragment, null, renderList(NODE_TYPES, (n) => {
19407
+ }, [createElementVNode("div", _hoisted_5, toDisplayString(unref(t)("creator")), 1), (openBlock(), createElementBlock(Fragment, null, renderList(NODE_TYPES, (n) => {
19284
19408
  return createElementVNode("button", {
19285
19409
  key: n.type,
19286
19410
  type: "button",
19287
19411
  class: "m-workflow__menu-item",
19288
19412
  onClick: ($event) => chooseNodeType(n.type)
19289
- }, [createElementVNode("span", null, toDisplayString(n.label), 1), createElementVNode("span", _hoisted_6, toDisplayString(n.kbd), 1)], 8, _hoisted_5);
19413
+ }, [createElementVNode("span", _hoisted_7, [createVNode(unref(Icon_default), { icon: n.icon }, null, 8, ["icon"]), createTextVNode(" " + toDisplayString(unref(t)(`workflow:${n.type}`)), 1)]), createElementVNode("span", _hoisted_8, toDisplayString(n.kbd), 1)], 8, _hoisted_6);
19290
19414
  }), 64))], 4)], 64)) : createCommentVNode("", true)
19291
19415
  ])) : createCommentVNode("", true);
19292
19416
  };
@@ -19294,22 +19418,18 @@ var Workflow_default = /* @__PURE__ */ defineComponent({
19294
19418
  });
19295
19419
  //#endregion
19296
19420
  //#region src/plugins/workflow.ts
19421
+ function placeholderImage(svg) {
19422
+ return `data:image/svg+xml,${encodeURIComponent(svg)}`;
19423
+ }
19424
+ var IMAGE_PLACEHOLDER = placeholderImage("<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"380\" height=\"280\" viewBox=\"0 0 380 280\" fill=\"none\"><rect width=\"380\" height=\"280\" rx=\"20\" fill=\"#f3f4f6\"/><rect x=\"124\" y=\"92\" width=\"132\" height=\"96\" rx=\"12\" stroke=\"#c8ccd4\" stroke-width=\"6\" stroke-linejoin=\"round\"/><circle cx=\"156\" cy=\"124\" r=\"12\" fill=\"#c8ccd4\"/><path d=\"M132 184l40-40 26 26 22-22 36 36\" stroke=\"#c8ccd4\" stroke-width=\"6\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>");
19425
+ var VIDEO_PLACEHOLDER = placeholderImage("<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"380\" height=\"280\" viewBox=\"0 0 380 280\" fill=\"none\"><rect width=\"380\" height=\"280\" rx=\"20\" fill=\"#f3f4f6\"/><circle cx=\"190\" cy=\"140\" r=\"48\" stroke=\"#c8ccd4\" stroke-width=\"6\"/><path d=\"M178 116l40 24-40 24z\" fill=\"#c8ccd4\"/></svg>");
19297
19426
  var DEFAULT_NODES = {
19298
19427
  text: {
19299
- label: "文字生成",
19300
- title: "✍️ 双击此处输入文字..",
19301
- body: ["可以在此输入提示词,比如画面描述、产品卖点、活动主题、场景描述、品牌 slogan 等内容。若暂时没有明确内容,也可先输入关键词或草稿,后续随时修改优化哦!", "也可以在底部输入框输入需求,让 AI 自动完成文字生成。"]
19428
+ title: "✍️ Double-click to add text",
19429
+ body: ["Or describe it below and let AI write for you."]
19302
19430
  },
19303
- image: {
19304
- label: "图片生成",
19305
- title: "🖼️ 双击此处描述画面..",
19306
- body: ["输入画面描述、风格、主体等内容,让 AI 自动完成图片生成。"]
19307
- },
19308
- video: {
19309
- label: "视频生成",
19310
- title: "🎬 双击此处描述视频..",
19311
- body: ["输入分镜、动作、风格等内容,让 AI 自动完成视频生成。"]
19312
- }
19431
+ image: { image: IMAGE_PLACEHOLDER },
19432
+ video: { image: VIDEO_PLACEHOLDER }
19313
19433
  };
19314
19434
  //#endregion
19315
19435
  //#region src/plugins/index.ts
@@ -19319,6 +19439,7 @@ var plugins = [
19319
19439
  clipboard_default,
19320
19440
  doc_default,
19321
19441
  edit_default,
19442
+ flexLayout_default,
19322
19443
  formatPaint_default,
19323
19444
  frame_default,
19324
19445
  history_default,
@@ -19372,26 +19493,32 @@ var plugins = [
19372
19493
  }
19373
19494
  function createWorkflowNode(type) {
19374
19495
  const t = getTemplate(type);
19375
- return {
19376
- name: t.label ?? type,
19496
+ const node = {
19497
+ name: t.label,
19377
19498
  style: {
19378
19499
  width: 380,
19379
19500
  height: 280,
19380
19501
  borderRadius: 20,
19381
- padding: 28,
19382
- fontSize: 16,
19383
- lineHeight: 1.6,
19384
- backgroundColor: "#ffffff",
19385
19502
  borderColor: "#ececf0",
19386
19503
  borderWidth: 1
19387
19504
  },
19388
- text: { content: buildContent(t) },
19389
19505
  meta: {
19390
19506
  inPptIs: "Shape",
19391
19507
  inCanvasIs: "Element2D",
19392
19508
  inEditorIs: `Workflow${type.charAt(0).toUpperCase()}${type.slice(1)}`
19393
19509
  }
19394
19510
  };
19511
+ if (t.image) node.foreground = { image: t.image };
19512
+ else {
19513
+ Object.assign(node.style, {
19514
+ padding: 28,
19515
+ fontSize: 16,
19516
+ lineHeight: 1.6,
19517
+ backgroundColor: "#ffffff"
19518
+ });
19519
+ node.text = { content: buildContent(t) };
19520
+ }
19521
+ return node;
19395
19522
  }
19396
19523
  function addWorkflowNode(type, position) {
19397
19524
  return addElement(createWorkflowNode(type), {
@@ -91,6 +91,9 @@ declare const _default: {
91
91
  collapse: string;
92
92
  statusbar: string;
93
93
  creator: string;
94
+ 'workflow:text': string;
95
+ 'workflow:image': string;
96
+ 'workflow:video': string;
94
97
  memoryManager: string;
95
98
  toolbelt: string;
96
99
  msaa: string;
@@ -91,6 +91,9 @@ declare const _default: {
91
91
  stepForward: string;
92
92
  collapse: string;
93
93
  creator: string;
94
+ 'workflow:text': string;
95
+ 'workflow:image': string;
96
+ 'workflow:video': string;
94
97
  memoryManager: string;
95
98
  toolbelt: string;
96
99
  msaa: string;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Drag-to-reorder for children of a flex/auto-layout container.
3
+ *
4
+ * `transform.ts` skips the absolute move for such a child; here we make it
5
+ * follow the cursor (a temporary left/top offset over its flow slot), swap
6
+ * order with its siblings as its centre crosses theirs, and on release drop
7
+ * the offset so it snaps back into its (new) slot.
8
+ *
9
+ * The sibling layout is derived analytically from sizes/gap captured once at
10
+ * drag start + the current children order (the order array updates
11
+ * synchronously on `moveChild`, but the rendered transforms only catch up on
12
+ * the next tick — so reading them back with `getObb` mid-drag is stale and
13
+ * makes the swap oscillate at the boundary). Structural changes run on the raw
14
+ * (non-reactive) nodes, else the canvas hands a Proxy to yoga's embind which
15
+ * throws a Proxy-invariant error and drops the child.
16
+ */
17
+ declare const _default: import("..").Plugin;
18
+ export default _default;
@@ -2,12 +2,20 @@ import type { Element2D } from 'modern-canvas';
2
2
  declare global {
3
3
  namespace Mce {
4
4
  interface WorkflowNodeTemplate {
5
- /** Layer-panel name (and header label). */
5
+ /**
6
+ * 覆盖节点名(写入 node.name)。不设时图层名走 i18n(key:workflow:<type>),
7
+ * 切换语言即时生效;菜单项始终走 i18n。
8
+ */
6
9
  label?: string;
7
10
  /** Bold first line shown inside the node. */
8
11
  title?: string;
9
12
  /** Gray hint paragraphs under the title. */
10
13
  body?: string[];
14
+ /**
15
+ * 默认占位图。设置后节点渲染这张图片而非 title/body 文字
16
+ * (图片/视频生成节点用它呈现一张默认图)。
17
+ */
18
+ image?: string;
11
19
  }
12
20
  interface Options {
13
21
  /** Override/extend the workflow node content templates, keyed by node type. */
@@ -29,6 +29,7 @@ import './plugins/autoNest'
29
29
  import './plugins/clipboard'
30
30
  import './plugins/doc'
31
31
  import './plugins/edit'
32
+ import './plugins/flexLayout'
32
33
  import './plugins/formatPaint'
33
34
  import './plugins/frame'
34
35
  import './plugins/history'
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mce",
3
3
  "type": "module",
4
- "version": "0.20.0",
4
+ "version": "0.22.0",
5
5
  "description": "A headless infinite canvas editor framework built on WebGL rendering, supports exporting to image, video, and PPT. Only the ESM.",
6
6
  "author": "wxm",
7
7
  "license": "MIT",
@@ -69,6 +69,7 @@
69
69
  },
70
70
  "peerDependencies": {
71
71
  "lottie-web": "^5",
72
+ "modern-gif": "^2",
72
73
  "typescript": ">=4.7",
73
74
  "vue": "^3.5.0",
74
75
  "yoga-layout": "^3"
@@ -77,6 +78,9 @@
77
78
  "lottie-web": {
78
79
  "optional": true
79
80
  },
81
+ "modern-gif": {
82
+ "optional": true
83
+ },
80
84
  "typescript": {
81
85
  "optional": true
82
86
  },