@tmagic/editor 1.7.11 → 1.7.13-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/es/Editor.vue_vue_type_script_setup_true_lang.js +6 -2
  2. package/dist/es/components/ScrollViewer.vue_vue_type_script_setup_true_lang.js +1 -1
  3. package/dist/es/components/Tree.vue_vue_type_script_setup_true_lang.js +6 -3
  4. package/dist/es/components/TreeNode.vue_vue_type_script_setup_true_lang.js +12 -7
  5. package/dist/es/index.js +2 -2
  6. package/dist/es/layouts/props-panel/PropsPanel.vue_vue_type_script_setup_true_lang.js +1 -1
  7. package/dist/es/layouts/sidebar/Sidebar.vue_vue_type_script_setup_true_lang.js +4 -2
  8. package/dist/es/layouts/sidebar/layer/LayerPanel.vue_vue_type_script_setup_true_lang.js +4 -1
  9. package/dist/es/layouts/workspace/Breadcrumb.vue_vue_type_script_setup_true_lang.js +87 -12
  10. package/dist/es/layouts/workspace/Workspace.vue_vue_type_script_setup_true_lang.js +5 -2
  11. package/dist/es/layouts/workspace/viewer/Stage.vue_vue_type_script_setup_true_lang.js +3 -2
  12. package/dist/es/services/editor.js +7 -5
  13. package/dist/es/services/props.js +2 -2
  14. package/dist/es/style.css +20 -0
  15. package/dist/es/utils/data-source/index.js +2 -3
  16. package/dist/es/utils/tree.js +3 -1
  17. package/dist/style.css +20 -0
  18. package/dist/tmagic-editor.umd.cjs +138 -37
  19. package/package.json +7 -7
  20. package/src/Editor.vue +2 -0
  21. package/src/components/ScrollViewer.vue +4 -1
  22. package/src/components/Tree.vue +4 -1
  23. package/src/components/TreeNode.vue +8 -8
  24. package/src/editorProps.ts +3 -0
  25. package/src/layouts/props-panel/PropsPanel.vue +1 -1
  26. package/src/layouts/sidebar/Sidebar.vue +4 -0
  27. package/src/layouts/sidebar/layer/LayerPanel.vue +11 -1
  28. package/src/layouts/workspace/Breadcrumb.vue +87 -6
  29. package/src/layouts/workspace/Workspace.vue +3 -1
  30. package/src/layouts/workspace/viewer/Stage.vue +7 -1
  31. package/src/services/editor.ts +11 -6
  32. package/src/services/props.ts +2 -2
  33. package/src/theme/breadcrumb.scss +24 -0
  34. package/src/type.ts +14 -1
  35. package/src/utils/data-source/index.ts +8 -4
  36. package/src/utils/tree.ts +5 -1
  37. package/types/index.d.ts +30 -7
@@ -4805,8 +4805,8 @@
4805
4805
  * @param type 组件类型
4806
4806
  * @returns 组件属性表单配置
4807
4807
  */
4808
- async getPropsConfig(type) {
4809
- if (type === "area") return await this.getPropsConfig("button");
4808
+ async getPropsConfig(type, data) {
4809
+ if (type === "area") return await this.getPropsConfig("button", data);
4810
4810
  return cloneDeep(this.state.propsConfigMap[(0, _tmagic_utils.toLine)(type)] || await this.fillConfig([]));
4811
4811
  }
4812
4812
  setPropsValues(values) {
@@ -6103,7 +6103,7 @@
6103
6103
  if (removedItems.length > 0 && pageForOp) this.pushOpHistory("remove", { removedItems }, pageForOp);
6104
6104
  this.emit("remove", nodes);
6105
6105
  }
6106
- async doUpdate(config, { changeRecords = [] } = {}) {
6106
+ async doUpdate(config, { changeRecords = [], selectedAfterUpdate = true } = {}) {
6107
6107
  const root = this.get("root");
6108
6108
  if (!root) throw new Error("root为空");
6109
6109
  if (!config?.id) throw new Error("没有配置或者配置缺少id值");
@@ -6130,10 +6130,12 @@
6130
6130
  const layout = await this.getLayout(node);
6131
6131
  if (Array.isArray(newConfig.items) && newLayout !== layout) newConfig = setChildrenLayout(newConfig, newLayout);
6132
6132
  parentNodeItems[index] = newConfig;
6133
- const nodes = this.get("nodes");
6134
- const targetIndex = nodes.findIndex((nodeItem) => `${nodeItem.id}` === `${newConfig.id}`);
6135
- nodes.splice(targetIndex, 1, newConfig);
6136
- this.set("nodes", [...nodes]);
6133
+ if (selectedAfterUpdate) {
6134
+ const nodes = this.get("nodes");
6135
+ const targetIndex = nodes.findIndex((nodeItem) => `${nodeItem.id}` === `${newConfig.id}`);
6136
+ nodes.splice(targetIndex, 1, newConfig);
6137
+ this.set("nodes", [...nodes]);
6138
+ }
6137
6139
  if ((0, _tmagic_utils.isPage)(newConfig) || (0, _tmagic_utils.isPageFragment)(newConfig)) this.set("page", newConfig);
6138
6140
  this.addModifiedNodeId(newConfig.id);
6139
6141
  return {
@@ -6877,6 +6879,8 @@
6877
6879
  if (nodeStatus[key] !== void 0 && status[key] !== void 0) nodeStatus[key] = Boolean(status[key]);
6878
6880
  });
6879
6881
  };
6882
+ /** 默认的组件树节点是否可展开的判断函数:当节点的子项中至少存在一个可见节点时认为可展开 */
6883
+ var defaultIsExpandable = (data, nodeStatusMap) => Array.isArray(data.items) && data.items.some((item) => nodeStatusMap.get(item.id)?.visible);
6880
6884
  //#endregion
6881
6885
  //#region packages/editor/src/hooks/use-filter.ts
6882
6886
  var useFilter = (nodeData, nodeStatusMap, filterNodeMethod) => {
@@ -7100,7 +7104,7 @@
7100
7104
  ]);
7101
7105
  //#endregion
7102
7106
  //#region packages/editor/src/utils/data-source/index.ts
7103
- var dataSourceFormConfig = (0, _tmagic_form.defineFormItem)({
7107
+ var dataSourceFormConfig = {
7104
7108
  type: "tab",
7105
7109
  items: [
7106
7110
  {
@@ -7162,7 +7166,7 @@
7162
7166
  }]
7163
7167
  }
7164
7168
  ]
7165
- });
7169
+ };
7166
7170
  var fillConfig$1 = (config) => [
7167
7171
  ...base_default(),
7168
7172
  ...config,
@@ -9018,7 +9022,7 @@
9018
9022
  return;
9019
9023
  }
9020
9024
  const type = node.value.type || (node.value.items ? "container" : "text");
9021
- curFormConfig.value = await propsService.getPropsConfig(type);
9025
+ curFormConfig.value = await propsService.getPropsConfig(type, { node: node.value });
9022
9026
  values.value = node.value;
9023
9027
  };
9024
9028
  (0, vue.watchEffect)(init);
@@ -9858,7 +9862,11 @@
9858
9862
  parentsId: { default: () => [] },
9859
9863
  nodeStatusMap: {},
9860
9864
  indent: { default: 0 },
9861
- nextLevelIndentIncrement: { default: 11 }
9865
+ nextLevelIndentIncrement: { default: 11 },
9866
+ isExpandable: {
9867
+ type: Function,
9868
+ default: defaultIsExpandable
9869
+ }
9862
9870
  },
9863
9871
  emits: [
9864
9872
  "node-dragstart",
@@ -9881,7 +9889,6 @@
9881
9889
  const selected = (0, vue.computed)(() => nodeStatus.value.selected);
9882
9890
  const visible = (0, vue.computed)(() => nodeStatus.value.visible);
9883
9891
  const draggable = (0, vue.computed)(() => nodeStatus.value.draggable);
9884
- const hasChildren = (0, vue.computed)(() => Array.isArray(props.data.items) && props.data.items.some((item) => props.nodeStatusMap.get(item.id)?.visible));
9885
9892
  const handleDragStart = (event) => {
9886
9893
  treeEmit?.("node-dragstart", event, props.data);
9887
9894
  };
@@ -9925,20 +9932,21 @@
9925
9932
  onMouseenter: mouseenterHandler
9926
9933
  }, [(0, vue.createVNode)(Icon_default, {
9927
9934
  class: "expand-icon",
9928
- style: (0, vue.normalizeStyle)(hasChildren.value ? "" : "color: transparent; cursor: default"),
9935
+ style: (0, vue.normalizeStyle)(__props.isExpandable(__props.data, __props.nodeStatusMap) ? "" : "color: transparent; cursor: default"),
9929
9936
  icon: expanded.value ? (0, vue.unref)(_element_plus_icons_vue.ArrowDown) : (0, vue.unref)(_element_plus_icons_vue.ArrowRight),
9930
9937
  onClick: expandHandler
9931
9938
  }, null, 8, ["style", "icon"]), (0, vue.createElementVNode)("div", {
9932
9939
  class: "tree-node-content",
9933
9940
  onClick: nodeClickHandler
9934
- }, [(0, vue.renderSlot)(_ctx.$slots, "tree-node-content", { data: __props.data }, () => [(0, vue.createElementVNode)("div", _hoisted_2$15, [(0, vue.renderSlot)(_ctx.$slots, "tree-node-label", { data: __props.data }, () => [(0, vue.createTextVNode)((0, vue.toDisplayString)(`${__props.data.name} (${__props.data.id})`), 1)])]), (0, vue.createElementVNode)("div", _hoisted_3$4, [(0, vue.renderSlot)(_ctx.$slots, "tree-node-tool", { data: __props.data })])])])], 38), hasChildren.value && expanded.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_4$3, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(__props.data.items, (item) => {
9941
+ }, [(0, vue.renderSlot)(_ctx.$slots, "tree-node-content", { data: __props.data }, () => [(0, vue.createElementVNode)("div", _hoisted_2$15, [(0, vue.renderSlot)(_ctx.$slots, "tree-node-label", { data: __props.data }, () => [(0, vue.createTextVNode)((0, vue.toDisplayString)(`${__props.data.name} (${__props.data.id})`), 1)])]), (0, vue.createElementVNode)("div", _hoisted_3$4, [(0, vue.renderSlot)(_ctx.$slots, "tree-node-tool", { data: __props.data })])])])], 38), __props.isExpandable(__props.data, __props.nodeStatusMap) && expanded.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_4$3, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(__props.data.items, (item) => {
9935
9942
  return (0, vue.openBlock)(), (0, vue.createBlock)(_component_TreeNode, {
9936
9943
  key: item.id,
9937
9944
  data: item,
9938
9945
  parent: __props.data,
9939
9946
  parentsId: [...__props.parentsId, __props.data.id],
9940
9947
  "node-status-map": __props.nodeStatusMap,
9941
- indent: __props.indent + __props.nextLevelIndentIncrement
9948
+ indent: __props.indent + __props.nextLevelIndentIncrement,
9949
+ "is-expandable": __props.isExpandable
9942
9950
  }, {
9943
9951
  "tree-node-content": (0, vue.withCtx)(({ data: nodeData }) => [(0, vue.renderSlot)(_ctx.$slots, "tree-node-content", { data: nodeData })]),
9944
9952
  "tree-node-label": (0, vue.withCtx)(({ data: nodeData }) => [(0, vue.renderSlot)(_ctx.$slots, "tree-node-label", { data: nodeData })]),
@@ -9949,7 +9957,8 @@
9949
9957
  "parent",
9950
9958
  "parentsId",
9951
9959
  "node-status-map",
9952
- "indent"
9960
+ "indent",
9961
+ "is-expandable"
9953
9962
  ]);
9954
9963
  }), 128))])) : (0, vue.createCommentVNode)("v-if", true)], 40, _hoisted_1$49)), [[vue.vShow, visible.value]]);
9955
9964
  };
@@ -9972,7 +9981,8 @@
9972
9981
  nodeStatusMap: {},
9973
9982
  indent: { default: 0 },
9974
9983
  nextLevelIndentIncrement: {},
9975
- emptyText: { default: "暂无数据" }
9984
+ emptyText: { default: "暂无数据" },
9985
+ isExpandable: {}
9976
9986
  },
9977
9987
  emits: [
9978
9988
  "node-dragover",
@@ -9999,7 +10009,8 @@
9999
10009
  data: item,
10000
10010
  indent: __props.indent,
10001
10011
  "next-level-indent-increment": __props.nextLevelIndentIncrement,
10002
- "node-status-map": __props.nodeStatusMap
10012
+ "node-status-map": __props.nodeStatusMap,
10013
+ "is-expandable": __props.isExpandable
10003
10014
  }, {
10004
10015
  "tree-node-content": (0, vue.withCtx)(({ data: nodeData }) => [(0, vue.renderSlot)(_ctx.$slots, "tree-node-content", { data: nodeData })]),
10005
10016
  "tree-node-label": (0, vue.withCtx)(({ data: nodeData }) => [(0, vue.renderSlot)(_ctx.$slots, "tree-node-label", { data: nodeData })]),
@@ -10009,7 +10020,8 @@
10009
10020
  "data",
10010
10021
  "indent",
10011
10022
  "next-level-indent-increment",
10012
- "node-status-map"
10023
+ "node-status-map",
10024
+ "is-expandable"
10013
10025
  ]);
10014
10026
  }), 128)) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_1$48, [(0, vue.createElementVNode)("p", null, (0, vue.toDisplayString)(__props.emptyText), 1)]))], 32);
10015
10027
  };
@@ -11444,7 +11456,8 @@
11444
11456
  layerContentMenu: {},
11445
11457
  indent: {},
11446
11458
  nextLevelIndentIncrement: {},
11447
- customContentMenu: { type: Function }
11459
+ customContentMenu: { type: Function },
11460
+ isExpandable: { type: Function }
11448
11461
  },
11449
11462
  setup(__props) {
11450
11463
  const services = useServices();
@@ -11484,6 +11497,7 @@
11484
11497
  "node-status-map": (0, vue.unref)(nodeStatusMap),
11485
11498
  indent: __props.indent,
11486
11499
  "next-level-indent-increment": __props.nextLevelIndentIncrement,
11500
+ "is-expandable": __props.isExpandable,
11487
11501
  onNodeDragover: (0, vue.unref)(handleDragOver),
11488
11502
  onNodeDragstart: (0, vue.unref)(handleDragStart),
11489
11503
  onNodeDragleave: (0, vue.unref)(handleDragLeave),
@@ -11501,6 +11515,7 @@
11501
11515
  "node-status-map",
11502
11516
  "indent",
11503
11517
  "next-level-indent-increment",
11518
+ "is-expandable",
11504
11519
  "onNodeDragover",
11505
11520
  "onNodeDragstart",
11506
11521
  "onNodeDragleave",
@@ -11676,7 +11691,8 @@
11676
11691
  layerContentMenu: {},
11677
11692
  indent: {},
11678
11693
  nextLevelIndentIncrement: {},
11679
- customContentMenu: {}
11694
+ customContentMenu: {},
11695
+ layerNodeIsExpandable: {}
11680
11696
  },
11681
11697
  setup(__props, { expose: __expose }) {
11682
11698
  const props = __props;
@@ -11715,7 +11731,8 @@
11715
11731
  layerContentMenu: props.layerContentMenu,
11716
11732
  customContentMenu: props.customContentMenu,
11717
11733
  indent: props.indent,
11718
- nextLevelIndentIncrement: props.nextLevelIndentIncrement
11734
+ nextLevelIndentIncrement: props.nextLevelIndentIncrement,
11735
+ isExpandable: props.layerNodeIsExpandable
11719
11736
  },
11720
11737
  component: LayerPanel_default,
11721
11738
  slots: {}
@@ -12084,7 +12101,7 @@
12084
12101
  (0, vue.createElementVNode)("div", {
12085
12102
  ref: "target",
12086
12103
  style: (0, vue.normalizeStyle)(style.value)
12087
- }, [(0, vue.renderSlot)(_ctx.$slots, "default")], 4),
12104
+ }, [(0, vue.renderSlot)(_ctx.$slots, "before"), (0, vue.renderSlot)(_ctx.$slots, "default")], 4),
12088
12105
  (0, vue.renderSlot)(_ctx.$slots, "content"),
12089
12106
  scrollHeight.value > __props.wrapHeight ? ((0, vue.openBlock)(), (0, vue.createBlock)(ScrollBar_default, {
12090
12107
  key: 0,
@@ -12673,6 +12690,7 @@
12673
12690
  },
12674
12691
  onClick: _cache[0] || (_cache[0] = ($event) => stageWrapRef.value?.container?.focus())
12675
12692
  }, {
12693
+ before: (0, vue.withCtx)(() => [(0, vue.renderSlot)(_ctx.$slots, "stage-top")]),
12676
12694
  content: (0, vue.withCtx)(() => [!__props.disabledStageOverlay ? ((0, vue.openBlock)(), (0, vue.createBlock)(StageOverlay_default, { key: 0 })) : (0, vue.createCommentVNode)("v-if", true), ((0, vue.openBlock)(), (0, vue.createBlock)(vue.Teleport, { to: "body" }, [(0, vue.createVNode)(ViewerMenu_default, {
12677
12695
  ref: "menu",
12678
12696
  "is-multi-select": isMultiSelect.value,
@@ -12691,7 +12709,7 @@
12691
12709
  onDrop: dropHandler,
12692
12710
  onDragover: dragoverHandler
12693
12711
  }, null, 36), (0, vue.createVNode)(NodeListMenu_default)]),
12694
- _: 1
12712
+ _: 3
12695
12713
  }, 8, [
12696
12714
  "width",
12697
12715
  "height",
@@ -12709,9 +12727,13 @@
12709
12727
  //#region packages/editor/src/layouts/workspace/Breadcrumb.vue?vue&type=script&setup=true&lang.ts
12710
12728
  var _hoisted_1$39 = {
12711
12729
  key: 0,
12712
- class: "m-editor-breadcrumb"
12730
+ class: "m-editor-breadcrumb-ellipsis"
12713
12731
  };
12714
- var _hoisted_2$12 = { key: 0 };
12732
+ var _hoisted_2$12 = {
12733
+ key: 2,
12734
+ class: "m-editor-breadcrumb-separator"
12735
+ };
12736
+ var COLLAPSE_RATIO = .8;
12715
12737
  var Breadcrumb_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ (0, vue.defineComponent)({
12716
12738
  name: "MEditorBreadcrumb",
12717
12739
  __name: "Breadcrumb",
@@ -12721,21 +12743,92 @@
12721
12743
  const nodes = (0, vue.computed)(() => editorService.get("nodes"));
12722
12744
  const root = (0, vue.computed)(() => editorService.get("root"));
12723
12745
  const path = (0, vue.computed)(() => (0, _tmagic_utils.getNodePath)(node.value?.id || "", root.value?.items || []));
12746
+ const containerRef = (0, vue.ref)(null);
12747
+ const collapsed = (0, vue.ref)(false);
12748
+ const displayPath = (0, vue.computed)(() => {
12749
+ const list = path.value;
12750
+ if (!collapsed.value || list.length <= 3) return list;
12751
+ return [
12752
+ list[0],
12753
+ {
12754
+ isEllipsis: true,
12755
+ id: "__ellipsis__",
12756
+ name: "..."
12757
+ },
12758
+ list[list.length - 2],
12759
+ list[list.length - 1]
12760
+ ];
12761
+ });
12762
+ const measureOverflow = async () => {
12763
+ if (collapsed.value) {
12764
+ collapsed.value = false;
12765
+ await (0, vue.nextTick)();
12766
+ }
12767
+ const el = containerRef.value;
12768
+ const parent = el?.parentElement;
12769
+ if (!el || !parent) return;
12770
+ const contentWidth = el.scrollWidth;
12771
+ const parentWidth = parent.clientWidth;
12772
+ if (parentWidth <= 0) return;
12773
+ collapsed.value = contentWidth > parentWidth * COLLAPSE_RATIO;
12774
+ };
12775
+ let resizeObserver = null;
12776
+ const observe = () => {
12777
+ resizeObserver?.disconnect();
12778
+ const el = containerRef.value;
12779
+ if (!el || typeof ResizeObserver === "undefined") return;
12780
+ resizeObserver = new ResizeObserver(() => {
12781
+ measureOverflow();
12782
+ });
12783
+ resizeObserver.observe(el);
12784
+ if (el.parentElement) resizeObserver.observe(el.parentElement);
12785
+ };
12786
+ (0, vue.onMounted)(() => {
12787
+ observe();
12788
+ measureOverflow();
12789
+ });
12790
+ (0, vue.onBeforeUnmount)(() => {
12791
+ resizeObserver?.disconnect();
12792
+ resizeObserver = null;
12793
+ });
12794
+ (0, vue.watch)(() => nodes.value.length, async () => {
12795
+ await (0, vue.nextTick)();
12796
+ observe();
12797
+ measureOverflow();
12798
+ });
12799
+ (0, vue.watch)(path, async () => {
12800
+ await (0, vue.nextTick)();
12801
+ measureOverflow();
12802
+ });
12724
12803
  const select = async (node) => {
12725
12804
  await editorService.select(node);
12726
12805
  editorService.get("stage")?.select(node.id);
12727
12806
  };
12728
12807
  return (_ctx, _cache) => {
12729
- return nodes.value.length === 1 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_1$39, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(path.value, (item, index) => {
12730
- return (0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: item.id }, [(0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicButton), {
12731
- link: "",
12732
- disabled: item.id === node.value?.id,
12733
- onClick: ($event) => select(item)
12808
+ return nodes.value.length === 1 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
12809
+ key: 0,
12810
+ ref_key: "containerRef",
12811
+ ref: containerRef,
12812
+ class: "m-editor-breadcrumb"
12813
+ }, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(displayPath.value, (item, index) => {
12814
+ return (0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: item.isEllipsis ? `ellipsis-${index}` : item.id }, [item.isEllipsis ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_1$39, "...")) : ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicTooltip), {
12815
+ key: 1,
12816
+ content: item.name,
12817
+ placement: "top",
12818
+ "show-after": 500
12734
12819
  }, {
12735
- default: (0, vue.withCtx)(() => [(0, vue.createTextVNode)((0, vue.toDisplayString)(item.name), 1)]),
12820
+ default: (0, vue.withCtx)(() => [(0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicButton), {
12821
+ class: "m-editor-breadcrumb-item",
12822
+ link: "",
12823
+ disabled: item.id === node.value?.id,
12824
+ onClick: ($event) => select(item)
12825
+ }, {
12826
+ default: (0, vue.withCtx)(() => [(0, vue.createTextVNode)((0, vue.toDisplayString)(item.name), 1)]),
12827
+ _: 2
12828
+ }, 1032, ["disabled", "onClick"])]),
12736
12829
  _: 2
12737
- }, 1032, ["disabled", "onClick"]), index < path.value.length - 1 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_2$12, "/")) : (0, vue.createCommentVNode)("v-if", true)], 64);
12738
- }), 128))])) : (0, vue.createCommentVNode)("v-if", true);
12830
+ }, 1032, ["content"])), index < displayPath.value.length - 1 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_2$12, "/")) : (0, vue.createCommentVNode)("v-if", true)], 64);
12831
+ }), 128))], 512)) : (0, vue.createCommentVNode)("v-if", true);
12739
12832
  };
12740
12833
  }
12741
12834
  });
@@ -12769,7 +12862,10 @@
12769
12862
  "disabled-stage-overlay": __props.disabledStageOverlay,
12770
12863
  "stage-content-menu": __props.stageContentMenu,
12771
12864
  "custom-content-menu": __props.customContentMenu
12772
- }, null, 8, [
12865
+ }, {
12866
+ "stage-top": (0, vue.withCtx)(() => [(0, vue.renderSlot)(_ctx.$slots, "stage-top")]),
12867
+ _: 3
12868
+ }, 8, [
12773
12869
  "stage-options",
12774
12870
  "disabled-stage-overlay",
12775
12871
  "stage-content-menu",
@@ -14229,6 +14325,7 @@
14229
14325
  canSelect: { type: Function },
14230
14326
  isContainer: { type: Function },
14231
14327
  customContentMenu: { type: Function },
14328
+ layerNodeIsExpandable: { type: Function },
14232
14329
  beforeDblclick: { type: Function },
14233
14330
  extendFormState: { type: Function },
14234
14331
  pageBarSortOptions: {},
@@ -14312,7 +14409,8 @@
14312
14409
  "layer-content-menu": __props.layerContentMenu,
14313
14410
  "custom-content-menu": __props.customContentMenu,
14314
14411
  indent: __props.treeIndent,
14315
- "next-level-indent-increment": __props.treeNextLevelIndentIncrement
14412
+ "next-level-indent-increment": __props.treeNextLevelIndentIncrement,
14413
+ "layer-node-is-expandable": __props.layerNodeIsExpandable
14316
14414
  }, {
14317
14415
  "layer-panel-header": (0, vue.withCtx)(() => [(0, vue.renderSlot)(_ctx.$slots, "layer-panel-header")]),
14318
14416
  "layer-node-content": (0, vue.withCtx)(({ data }) => [(0, vue.renderSlot)(_ctx.$slots, "layer-node-content", { data })]),
@@ -14335,13 +14433,15 @@
14335
14433
  "layer-content-menu",
14336
14434
  "custom-content-menu",
14337
14435
  "indent",
14338
- "next-level-indent-increment"
14436
+ "next-level-indent-increment",
14437
+ "layer-node-is-expandable"
14339
14438
  ])])]),
14340
14439
  workspace: (0, vue.withCtx)(() => [(0, vue.renderSlot)(_ctx.$slots, "workspace", { editorService: (0, vue.unref)(editor_default) }, () => [(0, vue.createVNode)(Workspace_default, {
14341
14440
  "disabled-stage-overlay": __props.disabledStageOverlay,
14342
14441
  "stage-content-menu": __props.stageContentMenu,
14343
14442
  "custom-content-menu": __props.customContentMenu
14344
14443
  }, {
14444
+ "stage-top": (0, vue.withCtx)(() => [(0, vue.renderSlot)(_ctx.$slots, "stage-top")]),
14345
14445
  stage: (0, vue.withCtx)(() => [(0, vue.renderSlot)(_ctx.$slots, "stage")]),
14346
14446
  "workspace-content": (0, vue.withCtx)(() => [(0, vue.renderSlot)(_ctx.$slots, "workspace-content", { editorService: (0, vue.unref)(editor_default) })]),
14347
14447
  _: 3
@@ -18854,6 +18954,7 @@
18854
18954
  exports.dataSourceService = dataSource_default;
18855
18955
  exports.debug = debug;
18856
18956
  exports.default = plugin_default;
18957
+ exports.defaultIsExpandable = defaultIsExpandable;
18857
18958
  exports.depService = dep_default;
18858
18959
  Object.defineProperty(exports, "designPlugin", {
18859
18960
  enumerable: true,
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.7.11",
2
+ "version": "1.7.13-beta.0",
3
3
  "name": "@tmagic/editor",
4
4
  "type": "module",
5
5
  "sideEffects": [
@@ -58,11 +58,11 @@
58
58
  "moveable": "^0.53.0",
59
59
  "serialize-javascript": "^7.0.0",
60
60
  "sortablejs": "^1.15.6",
61
- "@tmagic/design": "1.7.11",
62
- "@tmagic/stage": "1.7.11",
63
- "@tmagic/table": "1.7.11",
64
- "@tmagic/form": "1.7.11",
65
- "@tmagic/utils": "1.7.11"
61
+ "@tmagic/design": "1.7.13-beta.0",
62
+ "@tmagic/form": "1.7.13-beta.0",
63
+ "@tmagic/table": "1.7.13-beta.0",
64
+ "@tmagic/stage": "1.7.13-beta.0",
65
+ "@tmagic/utils": "1.7.13-beta.0"
66
66
  },
67
67
  "devDependencies": {
68
68
  "@types/events": "^3.0.3",
@@ -76,7 +76,7 @@
76
76
  "type-fest": "^5.2.0",
77
77
  "typescript": "^6.0.3",
78
78
  "vue": "^3.5.33",
79
- "@tmagic/core": "1.7.11"
79
+ "@tmagic/core": "1.7.13-beta.0"
80
80
  },
81
81
  "peerDependenciesMeta": {
82
82
  "typescript": {
package/src/Editor.vue CHANGED
@@ -26,6 +26,7 @@
26
26
  :custom-content-menu="customContentMenu"
27
27
  :indent="treeIndent"
28
28
  :next-level-indent-increment="treeNextLevelIndentIncrement"
29
+ :layer-node-is-expandable="layerNodeIsExpandable"
29
30
  >
30
31
  <template #layer-panel-header>
31
32
  <slot name="layer-panel-header"></slot>
@@ -85,6 +86,7 @@
85
86
  :stage-content-menu="stageContentMenu"
86
87
  :custom-content-menu="customContentMenu"
87
88
  >
89
+ <template #stage-top><slot name="stage-top"></slot></template>
88
90
  <template #stage><slot name="stage"></slot></template>
89
91
  <template #workspace-content><slot name="workspace-content" :editorService="editorService"></slot></template>
90
92
  </Workspace>
@@ -1,6 +1,7 @@
1
1
  <template>
2
2
  <div class="m-editor-scroll-viewer-container" ref="container">
3
3
  <div ref="target" :style="style">
4
+ <slot name="before"></slot>
4
5
  <slot></slot>
5
6
  </div>
6
7
 
@@ -29,7 +30,7 @@ import { computed, onBeforeUnmount, onMounted, ref, useTemplateRef, watch } from
29
30
 
30
31
  import { isNumber } from '@tmagic/utils';
31
32
 
32
- import type { ScrollViewerEvent } from '@editor/type';
33
+ import type { ScrollViewerEvent, ScrollViewerSlots } from '@editor/type';
33
34
  import { ScrollViewer } from '@editor/utils/scroll-viewer';
34
35
 
35
36
  import ScrollBar from './ScrollBar.vue';
@@ -38,6 +39,8 @@ defineOptions({
38
39
  name: 'MEditorScrollViewer',
39
40
  });
40
41
 
42
+ defineSlots<ScrollViewerSlots>();
43
+
41
44
  const props = withDefaults(
42
45
  defineProps<{
43
46
  width?: number | string;
@@ -8,6 +8,7 @@
8
8
  :indent="indent"
9
9
  :next-level-indent-increment="nextLevelIndentIncrement"
10
10
  :node-status-map="nodeStatusMap"
11
+ :is-expandable="isExpandable"
11
12
  >
12
13
  <template #tree-node-content="{ data: nodeData }">
13
14
  <slot name="tree-node-content" :data="nodeData"> </slot>
@@ -33,7 +34,7 @@ import { provide } from 'vue';
33
34
 
34
35
  import type { Id } from '@tmagic/core';
35
36
 
36
- import type { LayerNodeStatus, TreeNodeData } from '@editor/type';
37
+ import type { IsExpandableFunction, LayerNodeStatus, TreeNodeData } from '@editor/type';
37
38
 
38
39
  import TreeNode from './TreeNode.vue';
39
40
 
@@ -66,6 +67,8 @@ withDefaults(
66
67
  indent?: number;
67
68
  nextLevelIndentIncrement?: number;
68
69
  emptyText?: string;
70
+ /** 自定义判断节点是否可展开(即是否要展示为拥有子节点的形态)的函数 */
71
+ isExpandable?: IsExpandableFunction;
69
72
  }>(),
70
73
  {
71
74
  indent: 0,
@@ -20,7 +20,7 @@
20
20
  >
21
21
  <MIcon
22
22
  class="expand-icon"
23
- :style="hasChildren ? '' : 'color: transparent; cursor: default'"
23
+ :style="isExpandable(data, nodeStatusMap) ? '' : 'color: transparent; cursor: default'"
24
24
  :icon="expanded ? ArrowDown : ArrowRight"
25
25
  @click="expandHandler"
26
26
  ></MIcon>
@@ -37,7 +37,7 @@
37
37
  </div>
38
38
  </div>
39
39
 
40
- <div v-if="hasChildren && expanded" class="m-editor-tree-node-children">
40
+ <div v-if="isExpandable(data, nodeStatusMap) && expanded" class="m-editor-tree-node-children">
41
41
  <TreeNode
42
42
  v-for="item in data.items"
43
43
  :key="item.id"
@@ -46,6 +46,7 @@
46
46
  :parentsId="[...parentsId, data.id]"
47
47
  :node-status-map="nodeStatusMap"
48
48
  :indent="indent + nextLevelIndentIncrement"
49
+ :is-expandable="isExpandable"
49
50
  >
50
51
  <template #tree-node-content="{ data: nodeData }">
51
52
  <slot name="tree-node-content" :data="nodeData"> </slot>
@@ -68,8 +69,8 @@ import { ArrowDown, ArrowRight } from '@element-plus/icons-vue';
68
69
  import type { Id } from '@tmagic/core';
69
70
 
70
71
  import MIcon from '@editor/components/Icon.vue';
71
- import type { LayerNodeStatus, TreeNodeData } from '@editor/type';
72
- import { updateStatus } from '@editor/utils/tree';
72
+ import type { IsExpandableFunction, LayerNodeStatus, TreeNodeData } from '@editor/type';
73
+ import { defaultIsExpandable, updateStatus } from '@editor/utils/tree';
73
74
 
74
75
  defineSlots<{
75
76
  'tree-node-label'(_props: { data: TreeNodeData }): any;
@@ -100,11 +101,14 @@ const props = withDefaults(
100
101
  nodeStatusMap: Map<Id, LayerNodeStatus>;
101
102
  indent?: number;
102
103
  nextLevelIndentIncrement?: number;
104
+ /** 自定义判断节点是否可展开(即是否要展示为拥有子节点的形态)的函数 */
105
+ isExpandable?: IsExpandableFunction;
103
106
  }>(),
104
107
  {
105
108
  indent: 0,
106
109
  nextLevelIndentIncrement: 11,
107
110
  parentsId: () => [],
111
+ isExpandable: defaultIsExpandable,
108
112
  },
109
113
  );
110
114
 
@@ -123,10 +127,6 @@ const selected = computed(() => nodeStatus.value.selected);
123
127
  const visible = computed(() => nodeStatus.value.visible);
124
128
  const draggable = computed(() => nodeStatus.value.draggable);
125
129
 
126
- const hasChildren = computed(
127
- () => Array.isArray(props.data.items) && props.data.items.some((item) => props.nodeStatusMap.get(item.id)?.visible),
128
- );
129
-
130
130
  const handleDragStart = (event: DragEvent) => {
131
131
  treeEmit?.('node-dragstart', event, props.data);
132
132
  };
@@ -14,6 +14,7 @@ import type {
14
14
  ComponentGroup,
15
15
  CustomContentMenuFunction,
16
16
  DatasourceTypeOption,
17
+ IsExpandableFunction,
17
18
  MenuBarData,
18
19
  MenuButton,
19
20
  MenuComponent,
@@ -98,6 +99,8 @@ export interface EditorProps {
98
99
  isContainer?: (el: HTMLElement) => boolean | Promise<boolean>;
99
100
  /** 用于自定义组件树与画布的右键菜单 */
100
101
  customContentMenu?: CustomContentMenuFunction;
102
+ /** 用于自定义判断组件树节点是否可展开(即是否要展示为拥有子节点的形态) */
103
+ layerNodeIsExpandable?: IsExpandableFunction;
101
104
  /** 画布双击前的钩子函数,返回 false 则阻止默认的双击行为 */
102
105
  beforeDblclick?: (event: MouseEvent) => Promise<boolean | void> | boolean | void;
103
106
  extendFormState?: (state: FormState) => Record<string, any> | Promise<Record<string, any>>;
@@ -115,7 +115,7 @@ const init = async () => {
115
115
  }
116
116
 
117
117
  const type = node.value.type || (node.value.items ? 'container' : 'text');
118
- curFormConfig.value = await propsService.getPropsConfig(type);
118
+ curFormConfig.value = await propsService.getPropsConfig(type, { node: node.value });
119
119
  values.value = node.value;
120
120
  };
121
121
 
@@ -164,6 +164,7 @@ import { useServices } from '@editor/hooks/use-services';
164
164
  import {
165
165
  ColumnLayout,
166
166
  CustomContentMenuFunction,
167
+ type IsExpandableFunction,
167
168
  type MenuButton,
168
169
  type MenuComponent,
169
170
  type SideBarData,
@@ -191,6 +192,8 @@ const props = withDefaults(
191
192
  indent?: number;
192
193
  nextLevelIndentIncrement?: number;
193
194
  customContentMenu: CustomContentMenuFunction;
195
+ /** 自定义判断组件树节点是否可展开(即是否要展示为拥有子节点的形态)的函数 */
196
+ layerNodeIsExpandable?: IsExpandableFunction;
194
197
  }>(),
195
198
  {
196
199
  data: () => ({
@@ -248,6 +251,7 @@ const getItemConfig = (data: SideItem): SideComponent => {
248
251
  customContentMenu: props.customContentMenu,
249
252
  indent: props.indent,
250
253
  nextLevelIndentIncrement: props.nextLevelIndentIncrement,
254
+ isExpandable: props.layerNodeIsExpandable,
251
255
  },
252
256
  component: LayerPanel,
253
257
  slots: {},
@@ -12,6 +12,7 @@
12
12
  :node-status-map="nodeStatusMap"
13
13
  :indent="indent"
14
14
  :next-level-indent-increment="nextLevelIndentIncrement"
15
+ :is-expandable="isExpandable"
15
16
  @node-dragover="handleDragOver"
16
17
  @node-dragstart="handleDragStart"
17
18
  @node-dragleave="handleDragLeave"
@@ -56,7 +57,14 @@ import SearchInput from '@editor/components/SearchInput.vue';
56
57
  import Tree from '@editor/components/Tree.vue';
57
58
  import { useFilter } from '@editor/hooks/use-filter';
58
59
  import { useServices } from '@editor/hooks/use-services';
59
- import type { CustomContentMenuFunction, LayerPanelSlots, MenuButton, MenuComponent, TreeNodeData } from '@editor/type';
60
+ import type {
61
+ CustomContentMenuFunction,
62
+ IsExpandableFunction,
63
+ LayerPanelSlots,
64
+ MenuButton,
65
+ MenuComponent,
66
+ TreeNodeData,
67
+ } from '@editor/type';
60
68
 
61
69
  import LayerMenu from './LayerMenu.vue';
62
70
  import LayerNodeTool from './LayerNodeTool.vue';
@@ -76,6 +84,8 @@ defineProps<{
76
84
  indent?: number;
77
85
  nextLevelIndentIncrement?: number;
78
86
  customContentMenu: CustomContentMenuFunction;
87
+ /** 自定义判断组件树节点是否可展开(即是否要展示为拥有子节点的形态)的函数 */
88
+ isExpandable?: IsExpandableFunction;
79
89
  }>();
80
90
 
81
91
  const services = useServices();