@tmagic/editor 1.8.0-beta.21 → 1.8.0-beta.23

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/components/CodeBlockEditor.vue_vue_type_script_setup_true_lang.js +2 -1
  2. package/dist/es/components/Resizer.vue_vue_type_script_setup_true_lang.js +2 -1
  3. package/dist/es/fields/CondOpSelect.vue_vue_type_script_setup_true_lang.js +3 -1
  4. package/dist/es/fields/DataSourceFields.vue_vue_type_script_setup_true_lang.js +2 -1
  5. package/dist/es/fields/DataSourceInput.vue_vue_type_script_setup_true_lang.js +2 -1
  6. package/dist/es/fields/DataSourceMocks.vue_vue_type_script_setup_true_lang.js +2 -1
  7. package/dist/es/fields/DisplayConds.vue_vue_type_script_setup_true_lang.js +4 -2
  8. package/dist/es/fields/StyleSetter/components/Box.vue_vue_type_script_setup_true_lang.js +2 -2
  9. package/dist/es/fields/StyleSetter/pro/Background.vue_vue_type_script_setup_true_lang.js +6 -1
  10. package/dist/es/fields/StyleSetter/pro/Font.vue_vue_type_script_setup_true_lang.js +35 -3
  11. package/dist/es/fields/StyleSetter/pro/Position.vue_vue_type_script_setup_true_lang.js +26 -5
  12. package/dist/es/index.js +2 -2
  13. package/dist/es/initService.js +2 -1
  14. package/dist/es/layouts/props-panel/PropsPanel.vue_vue_type_script_setup_true_lang.js +23 -12
  15. package/dist/es/layouts/sidebar/ComponentListPanel.vue_vue_type_script_setup_true_lang.js +1 -1
  16. package/dist/es/layouts/sidebar/Sidebar.vue_vue_type_script_setup_true_lang.js +2 -1
  17. package/dist/es/layouts/sidebar/data-source/DataSourceConfigPanel.vue_vue_type_script_setup_true_lang.js +2 -1
  18. package/dist/es/layouts/sidebar/layer/LayerPanel.vue_vue_type_script_setup_true_lang.js +3 -2
  19. package/dist/es/services/codeBlock.js +4 -2
  20. package/dist/es/services/editor.js +12 -8
  21. package/dist/es/utils/dep/collect-worker-client.js +67 -27
  22. package/dist/es/utils/dep/worker.js +1 -1
  23. package/dist/es/utils/type-match-rules.js +24 -36
  24. package/dist/tmagic-editor.umd.cjs +413 -306
  25. package/package.json +12 -12
  26. package/src/fields/StyleSetter/components/Box.vue +1 -1
  27. package/src/fields/StyleSetter/components/Position.vue +1 -1
  28. package/src/fields/StyleSetter/pro/Background.vue +7 -0
  29. package/src/fields/StyleSetter/pro/Font.vue +57 -0
  30. package/src/fields/StyleSetter/pro/Position.vue +31 -0
  31. package/src/layouts/props-panel/PropsPanel.vue +30 -16
  32. package/src/layouts/sidebar/ComponentListPanel.vue +5 -1
  33. package/src/layouts/sidebar/layer/LayerPanel.vue +1 -1
  34. package/src/services/editor.ts +27 -8
  35. package/src/utils/dep/collect-worker-client.ts +97 -31
  36. package/src/utils/type-match-rules.ts +41 -34
  37. package/types/index.d.ts +106 -153
@@ -119,7 +119,8 @@ var CodeBlockEditor_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
119
119
  const closedHandler = () => {
120
120
  changedValue.value = void 0;
121
121
  };
122
- const { boxPosition, calcBoxPosition } = useNextFloatBoxPosition(uiService, inject("parentFloating", ref(null)));
122
+ const parentFloating = inject("parentFloating", ref(null));
123
+ const { boxPosition, calcBoxPosition } = useNextFloatBoxPosition(uiService, parentFloating);
123
124
  const frameworkWidth = computed(() => uiService.get("frameworkRect")?.width || 0);
124
125
  watch(boxVisible, (visible) => {
125
126
  nextTick(() => {
@@ -7,7 +7,8 @@ var Resizer_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCo
7
7
  emits: ["change"],
8
8
  setup(__props, { emit: __emit }) {
9
9
  const emit = __emit;
10
- const { isDragging } = useGetSo(useTemplateRef("target"), emit);
10
+ const targetEl = useTemplateRef("target");
11
+ const { isDragging } = useGetSo(targetEl, emit);
11
12
  return (_ctx, _cache) => {
12
13
  return openBlock(), createElementBlock("span", {
13
14
  ref: "target",
@@ -30,7 +30,9 @@ var CondOpSelect_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ def
30
30
  const optionComponent = getDesignConfig("components")?.option;
31
31
  const options = computed(() => {
32
32
  const [id, ...fieldNames] = [...props.config.parentFields || [], ...props.model.field];
33
- return getCondOpOptionsByFieldType(getFieldType(dataSourceService.getDataSourceById(id), fieldNames));
33
+ const ds = dataSourceService.getDataSourceById(id);
34
+ const type = getFieldType(ds, fieldNames);
35
+ return getCondOpOptionsByFieldType(type);
34
36
  });
35
37
  const fieldChangeHandler = (v) => {
36
38
  emit("change", v);
@@ -315,7 +315,8 @@ var DataSourceFields_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
315
315
  const addDialogVisible = useModel(__props, "visible");
316
316
  const addFromJsonDialogVisible = useModel(__props, "visible1");
317
317
  const { height: editorHeight } = useEditorContentHeight();
318
- const { boxPosition, calcBoxPosition } = useNextFloatBoxPosition(uiService, inject("parentFloating", ref(null)));
318
+ const parentFloating = inject("parentFloating", ref(null));
319
+ const { boxPosition, calcBoxPosition } = useNextFloatBoxPosition(uiService, parentFloating);
319
320
  const frameworkWidth = computed(() => uiService.get("frameworkRect")?.width || 0);
320
321
  /**
321
322
  * 由 DataSourceConfigPanel 注入:打开数据源详情后需要直接打开的字段路径(字段名数组)。
@@ -128,7 +128,8 @@ var DataSourceInput_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
128
128
  */
129
129
  const fieldQuerySearch = (queryString, leftAngleIndex, dotIndex, cb) => {
130
130
  let result = [];
131
- const keys = getKeysArray(queryString.substring(leftAngleIndex + 1, dotIndex));
131
+ const dsKey = queryString.substring(leftAngleIndex + 1, dotIndex);
132
+ const keys = getKeysArray(dsKey);
132
133
  const dsId = keys.shift();
133
134
  const ds = dataSources.value.find((ds) => ds.id === dsId);
134
135
  if (!ds) {
@@ -215,7 +215,8 @@ var DataSourceMocks_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
215
215
  };
216
216
  const addDialogVisible = useModel(__props, "visible");
217
217
  const { height: editorHeight } = useEditorContentHeight();
218
- const { boxPosition, calcBoxPosition } = useNextFloatBoxPosition(uiService, inject("parentFloating", ref(null)));
218
+ const parentFloating = inject("parentFloating", ref(null));
219
+ const { boxPosition, calcBoxPosition } = useNextFloatBoxPosition(uiService, parentFloating);
219
220
  const frameworkWidth = computed(() => uiService.get("frameworkRect")?.width || 0);
220
221
  return (_ctx, _cache) => {
221
222
  return openBlock(), createElementBlock("div", _hoisted_1, [
@@ -33,7 +33,8 @@ var DisplayConds_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ def
33
33
  const parentFields = computed(() => filterFunction(mForm, props.config.parentFields, props) || []);
34
34
  const fieldOnChange = (_formState, v, { model }) => {
35
35
  const [id, ...fieldNames] = [...parentFields.value, ...v];
36
- const type = getFieldType(dataSourceService.getDataSourceById(id), fieldNames);
36
+ const ds = dataSourceService.getDataSourceById(id);
37
+ const type = getFieldType(ds, fieldNames);
37
38
  if (type === "number") model.value = Number(model.value);
38
39
  else if (type === "boolean") model.value = Boolean(model.value);
39
40
  else if (type === "null") model.value = null;
@@ -131,7 +132,8 @@ var DisplayConds_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ def
131
132
  name: "value",
132
133
  type: (_mForm, { model }) => {
133
134
  const [id, ...fieldNames] = [...parentFields.value, ...model.field];
134
- const type = getFieldType(dataSourceService.getDataSourceById(id), fieldNames);
135
+ const ds = dataSourceService.getDataSourceById(id);
136
+ const type = getFieldType(ds, fieldNames);
135
137
  if (type === "number") return "number";
136
138
  if (type === "boolean") return "select";
137
139
  if (type === "null") return "display";
@@ -7,7 +7,7 @@ var _hoisted_2 = {
7
7
  };
8
8
  var _hoisted_3 = { class: "next-input" };
9
9
  var _hoisted_4 = [
10
- "model-value",
10
+ "value",
11
11
  "title",
12
12
  "disabled",
13
13
  "onChange"
@@ -69,7 +69,7 @@ var Box_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCompon
69
69
  key: index,
70
70
  class: normalizeClass(item.class)
71
71
  }, [item.text ? (openBlock(), createElementBlock("span", _hoisted_2, toDisplayString(item.text), 1)) : createCommentVNode("v-if", true), createElementVNode("span", _hoisted_3, [createElementVNode("input", {
72
- "model-value": __props.model[item.name],
72
+ value: __props.model[item.name],
73
73
  placeholder: "0",
74
74
  title: __props.model[item.name],
75
75
  disabled: __props.disabled,
@@ -4,6 +4,7 @@ import RepeatX_default from "../icons/background-repeat/RepeatX.js";
4
4
  import RepeatY_default from "../icons/background-repeat/RepeatY.js";
5
5
  import NoRepeat_default from "../icons/background-repeat/NoRepeat.js";
6
6
  import { MContainer, defineFormConfig } from "@tmagic/form";
7
+ import { appendValidateSuggestion } from "@tmagic/design";
7
8
  import { Fragment, createBlock, createElementBlock, defineComponent, markRaw, openBlock, renderList, unref } from "vue";
8
9
  //#region packages/editor/src/fields/StyleSetter/pro/Background.vue?vue&type=script&setup=true&lang.ts
9
10
  var Background_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
@@ -26,7 +27,11 @@ var Background_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defin
26
27
  text: "背景色",
27
28
  labelWidth: "68px",
28
29
  type: "data-source-field-select",
29
- fieldConfig: { type: "colorPicker" }
30
+ fieldConfig: { type: "colorPicker" },
31
+ rules: [{
32
+ typeMatch: true,
33
+ message: appendValidateSuggestion("背景色应为字符串", "请参考以下示例值:\"#000000\"")
34
+ }]
30
35
  },
31
36
  {
32
37
  name: "backgroundImage",
@@ -1,7 +1,9 @@
1
+ import { validateDataSourceFieldSelectValue } from "../../../utils/type-match-rules.js";
1
2
  import Left_default from "../icons/text-align/Left.js";
2
3
  import Center_default from "../icons/text-align/Center.js";
3
4
  import Right_default from "../icons/text-align/Right.js";
4
5
  import { MContainer, defineFormConfig } from "@tmagic/form";
6
+ import { appendValidateSuggestion } from "@tmagic/design";
5
7
  import { Fragment, createBlock, createElementBlock, defineComponent, markRaw, openBlock, renderList, unref } from "vue";
6
8
  //#region packages/editor/src/fields/StyleSetter/pro/Font.vue?vue&type=script&setup=true&lang.ts
7
9
  var Font_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
@@ -25,7 +27,11 @@ var Font_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCompo
25
27
  name: "fontSize",
26
28
  text: "字号",
27
29
  type: "data-source-field-select",
28
- fieldConfig: { type: "text" }
30
+ fieldConfig: { type: "text" },
31
+ rules: [{
32
+ typeMatch: true,
33
+ message: appendValidateSuggestion("字号应为字符串或数字", "请参考以下示例值:24 或 \"24\"")
34
+ }]
29
35
  }, {
30
36
  labelWidth: "68px",
31
37
  name: "lineHeight",
@@ -39,20 +45,46 @@ var Font_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCompo
39
45
  text: "字重",
40
46
  labelWidth: "68px",
41
47
  type: "data-source-field-select",
48
+ dataSourceFieldType: ["string", "number"],
42
49
  fieldConfig: {
43
50
  type: "select",
51
+ allowCreate: true,
44
52
  options: ["normal", "bold"].concat(Array(7).fill(1).map((x, i) => `${i + 1}00`)).map((item) => ({
45
53
  value: item,
46
54
  text: item
47
55
  }))
48
- }
56
+ },
57
+ rules: [{ typeMatch: false }, { validator: ({ value, callback }, { config, model, prop }, mForm) => {
58
+ if (value === "" || value === null || value === void 0) return callback();
59
+ const result = validateDataSourceFieldSelectValue(value, {
60
+ fieldType: "data-source-field-select",
61
+ mForm,
62
+ props: {
63
+ config,
64
+ model,
65
+ prop
66
+ }
67
+ }, { validatePlainValue: (plainValue) => {
68
+ if (typeof plainValue === "string" || typeof plainValue === "number" && !Number.isNaN(plainValue)) return;
69
+ return "字重应为字符串或数字";
70
+ } });
71
+ if (result && typeof result.then === "function") {
72
+ result.then((error) => callback(error), (error) => callback(error));
73
+ return;
74
+ }
75
+ return callback(result);
76
+ } }]
49
77
  },
50
78
  {
51
79
  labelWidth: "68px",
52
80
  name: "color",
53
81
  text: "颜色",
54
82
  type: "data-source-field-select",
55
- fieldConfig: { type: "colorPicker" }
83
+ fieldConfig: { type: "colorPicker" },
84
+ rules: [{
85
+ typeMatch: true,
86
+ message: appendValidateSuggestion("颜色应为字符串", "请参考以下示例值:\"#000000\"")
87
+ }]
56
88
  },
57
89
  {
58
90
  name: "textAlign",
@@ -1,4 +1,5 @@
1
1
  import { MContainer, defineFormConfig } from "@tmagic/form";
2
+ import { appendValidateSuggestion } from "@tmagic/design";
2
3
  import { Fragment, createBlock, createElementBlock, defineComponent, openBlock, renderList, unref } from "vue";
3
4
  //#region packages/editor/src/fields/StyleSetter/pro/Position.vue?vue&type=script&setup=true&lang.ts
4
5
  var Position_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
@@ -44,12 +45,20 @@ var Position_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineC
44
45
  name: "left",
45
46
  type: "data-source-field-select",
46
47
  text: "left",
47
- fieldConfig: { type: "text" }
48
+ fieldConfig: { type: "text" },
49
+ rules: [{
50
+ typeMatch: true,
51
+ message: appendValidateSuggestion("left 应为字符串", "请参考以下示例值:\"10\"")
52
+ }]
48
53
  }, {
49
54
  name: "top",
50
55
  type: "data-source-field-select",
51
56
  text: "top",
52
- fieldConfig: { type: "text" }
57
+ fieldConfig: { type: "text" },
58
+ rules: [{
59
+ typeMatch: true,
60
+ message: appendValidateSuggestion("top 应为字符串", "请参考以下示例值:\"10\"")
61
+ }]
53
62
  }]
54
63
  },
55
64
  {
@@ -60,12 +69,20 @@ var Position_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineC
60
69
  name: "right",
61
70
  type: "data-source-field-select",
62
71
  text: "right",
63
- fieldConfig: { type: "text" }
72
+ fieldConfig: { type: "text" },
73
+ rules: [{
74
+ typeMatch: true,
75
+ message: appendValidateSuggestion("right 应为字符串", "请参考以下示例值:\"10\"")
76
+ }]
64
77
  }, {
65
78
  name: "bottom",
66
79
  type: "data-source-field-select",
67
80
  text: "bottom",
68
- fieldConfig: { type: "text" }
81
+ fieldConfig: { type: "text" },
82
+ rules: [{
83
+ typeMatch: true,
84
+ message: appendValidateSuggestion("bottom 应为字符串", "请参考以下示例值:\"10\"")
85
+ }]
69
86
  }]
70
87
  },
71
88
  {
@@ -73,7 +90,11 @@ var Position_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineC
73
90
  name: "zIndex",
74
91
  text: "zIndex",
75
92
  type: "data-source-field-select",
76
- fieldConfig: { type: "text" }
93
+ fieldConfig: { type: "text" },
94
+ rules: [{
95
+ typeMatch: true,
96
+ message: appendValidateSuggestion("zIndex 应为数字", "请参考以下示例值:10")
97
+ }]
77
98
  }
78
99
  ]);
79
100
  const change = (value, eventData) => {
package/dist/es/index.js CHANGED
@@ -31,7 +31,7 @@ import { IdleTask } from "./utils/dep/idle-task.js";
31
31
  import { ScrollViewer } from "./utils/scroll-viewer.js";
32
32
  import codeBlock_default from "./services/codeBlock.js";
33
33
  import dataSource_default from "./services/dataSource.js";
34
- import { ALL_COND_OPS, editorTypeMatchRules } from "./utils/type-match-rules.js";
34
+ import { ALL_COND_OPS, editorTypeMatchRules, validateDataSourceFieldSelectValue } from "./utils/type-match-rules.js";
35
35
  import events_default from "./services/events.js";
36
36
  import { EVENT_NAME_VALUE_SEPARATOR, collectEventNameOptionValues, getCompActionAllowedValues, getCompActionOptions, getEventNameAllowedValues, getEventNameOptions, isEventNameCheckStrictly, normalizeCompActionValue } from "./utils/event.js";
37
37
  import monaco_editor_default from "./utils/monaco-editor.js";
@@ -92,4 +92,4 @@ export * from "@tmagic/table";
92
92
  export * from "@tmagic/stage";
93
93
  export * from "@tmagic/design";
94
94
  export * from "@tmagic/utils";
95
- export { ALL_COND_OPS, CODE_DRAFT_STORAGE_KEY, COPY_CODE_STORAGE_KEY, COPY_DS_STORAGE_KEY, COPY_STORAGE_KEY, CodeBlockEditor_default as CodeBlockEditor, CodeBlockList_default as CodeBlockList, CodeBlockListPanel_default as CodeBlockListPanel, CodeDeleteErrorType, CodeSelect_default as CodeSelect, CodeSelectCol_default as CodeSelectCol, ColumnLayout, CompareForm_default as CompareForm, ComponentListPanel_default as ComponentListPanel, CondOpSelect_default as CondOpSelect, ContentMenu_default as ContentMenu, DEFAULT_LEFT_COLUMN_WIDTH, DEFAULT_RIGHT_COLUMN_WIDTH, DataSourceAddButton_default as DataSourceAddButton, DataSourceConfigPanel_default as DataSourceConfigPanel, Index_default as DataSourceFieldSelect, DataSourceFields_default as DataSourceFields, DataSourceInput_default as DataSourceInput, DataSourceMethodSelect_default as DataSourceMethodSelect, DataSourceMethods_default as DataSourceMethods, DataSourceMocks_default as DataSourceMocks, DataSourceSelect_default as DataSourceSelect, DepTargetType, DisplayConds_default as DisplayConds, DragType, EVENT_NAME_VALUE_SEPARATOR, EventSelect_default as EventSelect, Fixed2Other, FloatingBox_default as FloatingBox, H_GUIDE_LINE_STORAGE_KEY, HistoryDiffDialog_default as HistoryDiffDialog, Bucket_default as HistoryListBucket, BucketTab_default as HistoryListBucketTab, Icon_default as Icon, IdleTask, KeyBindingCommand, KeyValue_default as KeyValue, Keys, LEFT_COLUMN_WIDTH_STORAGE_KEY, LayerNodeContent_default as LayerNodeContent, LayerOffset, LayerPanel_default as LayerPanel, Layout, SplitView_default as LayoutContainer, MIN_CENTER_COLUMN_WIDTH, MIN_LEFT_COLUMN_WIDTH, MIN_RIGHT_COLUMN_WIDTH, PROPS_PANEL_WIDTH_STORAGE_KEY, PageFragmentSelect_default as PageFragmentSelect, FormPanel_default as PropsFormPanel, PropsPanel_default as PropsPanel, RIGHT_COLUMN_WIDTH_STORAGE_KEY, Resizer_default as Resizer, ScrollViewer, SideItemKey, SplitView_default as SplitView, StageCore, Index_default$1 as StyleSetter, CodeEditor_default as TMagicCodeEditor, Editor_default as TMagicEditor, ToolButton_default as ToolButton, Tree_default as Tree, TreeNode_default as TreeNode, UI_SELECT_MODE_EVENT_NAME, UndoRedo, V_GUIDE_LINE_STORAGE_KEY, ViewForm_default as ViewForm, advancedTabConfig, arrayOptions, beforePaste, booleanOptions, buildChangeRecords, calcAlignCenterStyle, calcLayerTargetIndex, calcMoveStyle, canUsePluginMethods, change2Fixed, classifyDragSources, codeBlock_default as codeBlockService, collectEventNameOptionValues, collectRelatedNodes, componentList_default as componentListService, confirmHistoryAction, createStackStep, dataSource_default as dataSourceService, debug, plugin_default as default, defaultIsExpandable, dep_default as depService, describeRevertStep, describeStepForRevert, deserializeStacks, designPlugin, detectStackOpType, detectTargetId, detectTargetName, displayTabConfig, editorNodeMergeCustomizer, editor_default as editorService, editorTypeMatchRules, eqOptions, error, eventTabConfig, events_default as eventsService, fillConfig, fixNodeLeft, fixNodePosition, formPlugin, generatePageName, generatePageNameByApp, getAddParent, getCascaderOptionsFromFields, getCodeBlockFormConfig, getCompActionAllowedValues, getCompActionOptions, getCondOpOptionsByFieldType, getDefaultConfig, getDisplayField, getEditorConfig, getEventNameAllowedValues, getEventNameOptions, getFieldType, getFormConfig, getFormValue, getGuideLineFromCache, getInitPositionStyle, getLastPushedHistoryIds, getNodeIndex, getOrCreateStack, getPageFragmentList, getPageList, getPageNameList, getPositionInContainer, getRelativeStyle, history_default as historyService, idbDelete, idbGet, idbSet, info, isEventNameCheckStrictly, isGlobalFlat, isIncludeDataSource, isIndexedDBSupported, keybinding_default as keybindingService, monaco_editor_default as loadMonaco, log, markStackSaved, mergeSteps, moveItemsInContainer, normalizeCompActionValue, numberOptions, openIndexedDB, props_default as propsService, removeStyleDisplayConfig, resolveFieldByPath, resolveSelectedNode, serializeConfig, serializeStacks, setChildrenLayout, setEditorConfig, setLayout, stageOverlay_default as stageOverlayService, storage_default as storageService, styleTabConfig, tablePlugin, toggleFixedPosition, ui_default as uiService, undoFloor, updateStatus, useCodeBlockEdit, useCompareForm, useEditorContentHeight, useFilter, useFloatBox, useGetSo, useHistoryRevert, useNextFloatBoxPosition, useNodeStatus, useServices, useStage, useWindowRect, warn };
95
+ export { ALL_COND_OPS, CODE_DRAFT_STORAGE_KEY, COPY_CODE_STORAGE_KEY, COPY_DS_STORAGE_KEY, COPY_STORAGE_KEY, CodeBlockEditor_default as CodeBlockEditor, CodeBlockList_default as CodeBlockList, CodeBlockListPanel_default as CodeBlockListPanel, CodeDeleteErrorType, CodeSelect_default as CodeSelect, CodeSelectCol_default as CodeSelectCol, ColumnLayout, CompareForm_default as CompareForm, ComponentListPanel_default as ComponentListPanel, CondOpSelect_default as CondOpSelect, ContentMenu_default as ContentMenu, DEFAULT_LEFT_COLUMN_WIDTH, DEFAULT_RIGHT_COLUMN_WIDTH, DataSourceAddButton_default as DataSourceAddButton, DataSourceConfigPanel_default as DataSourceConfigPanel, Index_default as DataSourceFieldSelect, DataSourceFields_default as DataSourceFields, DataSourceInput_default as DataSourceInput, DataSourceMethodSelect_default as DataSourceMethodSelect, DataSourceMethods_default as DataSourceMethods, DataSourceMocks_default as DataSourceMocks, DataSourceSelect_default as DataSourceSelect, DepTargetType, DisplayConds_default as DisplayConds, DragType, EVENT_NAME_VALUE_SEPARATOR, EventSelect_default as EventSelect, Fixed2Other, FloatingBox_default as FloatingBox, H_GUIDE_LINE_STORAGE_KEY, HistoryDiffDialog_default as HistoryDiffDialog, Bucket_default as HistoryListBucket, BucketTab_default as HistoryListBucketTab, Icon_default as Icon, IdleTask, KeyBindingCommand, KeyValue_default as KeyValue, Keys, LEFT_COLUMN_WIDTH_STORAGE_KEY, LayerNodeContent_default as LayerNodeContent, LayerOffset, LayerPanel_default as LayerPanel, Layout, SplitView_default as LayoutContainer, MIN_CENTER_COLUMN_WIDTH, MIN_LEFT_COLUMN_WIDTH, MIN_RIGHT_COLUMN_WIDTH, PROPS_PANEL_WIDTH_STORAGE_KEY, PageFragmentSelect_default as PageFragmentSelect, FormPanel_default as PropsFormPanel, PropsPanel_default as PropsPanel, RIGHT_COLUMN_WIDTH_STORAGE_KEY, Resizer_default as Resizer, ScrollViewer, SideItemKey, SplitView_default as SplitView, StageCore, Index_default$1 as StyleSetter, CodeEditor_default as TMagicCodeEditor, Editor_default as TMagicEditor, ToolButton_default as ToolButton, Tree_default as Tree, TreeNode_default as TreeNode, UI_SELECT_MODE_EVENT_NAME, UndoRedo, V_GUIDE_LINE_STORAGE_KEY, ViewForm_default as ViewForm, advancedTabConfig, arrayOptions, beforePaste, booleanOptions, buildChangeRecords, calcAlignCenterStyle, calcLayerTargetIndex, calcMoveStyle, canUsePluginMethods, change2Fixed, classifyDragSources, codeBlock_default as codeBlockService, collectEventNameOptionValues, collectRelatedNodes, componentList_default as componentListService, confirmHistoryAction, createStackStep, dataSource_default as dataSourceService, debug, plugin_default as default, defaultIsExpandable, dep_default as depService, describeRevertStep, describeStepForRevert, deserializeStacks, designPlugin, detectStackOpType, detectTargetId, detectTargetName, displayTabConfig, editorNodeMergeCustomizer, editor_default as editorService, editorTypeMatchRules, eqOptions, error, eventTabConfig, events_default as eventsService, fillConfig, fixNodeLeft, fixNodePosition, formPlugin, generatePageName, generatePageNameByApp, getAddParent, getCascaderOptionsFromFields, getCodeBlockFormConfig, getCompActionAllowedValues, getCompActionOptions, getCondOpOptionsByFieldType, getDefaultConfig, getDisplayField, getEditorConfig, getEventNameAllowedValues, getEventNameOptions, getFieldType, getFormConfig, getFormValue, getGuideLineFromCache, getInitPositionStyle, getLastPushedHistoryIds, getNodeIndex, getOrCreateStack, getPageFragmentList, getPageList, getPageNameList, getPositionInContainer, getRelativeStyle, history_default as historyService, idbDelete, idbGet, idbSet, info, isEventNameCheckStrictly, isGlobalFlat, isIncludeDataSource, isIndexedDBSupported, keybinding_default as keybindingService, monaco_editor_default as loadMonaco, log, markStackSaved, mergeSteps, moveItemsInContainer, normalizeCompActionValue, numberOptions, openIndexedDB, props_default as propsService, removeStyleDisplayConfig, resolveFieldByPath, resolveSelectedNode, serializeConfig, serializeStacks, setChildrenLayout, setEditorConfig, setLayout, stageOverlay_default as stageOverlayService, storage_default as storageService, styleTabConfig, tablePlugin, toggleFixedPosition, ui_default as uiService, undoFloor, updateStatus, useCodeBlockEdit, useCompareForm, useEditorContentHeight, useFilter, useFloatBox, useGetSo, useHistoryRevert, useNextFloatBoxPosition, useNodeStatus, useServices, useStage, useWindowRect, validateDataSourceFieldSelectValue, warn };
@@ -329,7 +329,8 @@ var initServiceEvents = (props, emit, { editorService, codeBlockService, dataSou
329
329
  const root = editorService.get("root");
330
330
  if (!root) return;
331
331
  const handler = async () => {
332
- const nodes = getNodes(Object.keys(root.dataSourceDeps?.[id] || {}), root.items);
332
+ const nodeIds = Object.keys(root.dataSourceDeps?.[id] || {});
333
+ const nodes = getNodes(nodeIds, root.items);
333
334
  if (!(await Promise.all([
334
335
  collectIdle(nodes, false, DepTargetType.DATA_SOURCE),
335
336
  collectIdle(nodes, false, DepTargetType.DATA_SOURCE_COND),
@@ -68,22 +68,33 @@ var PropsPanel_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defin
68
68
  const submit = async (v, eventData, error, source = "props") => {
69
69
  try {
70
70
  if (!v.id) v.id = values.value.id;
71
- const newValue = {
72
- ...v,
73
- style: {}
74
- };
75
- if (v.style) if (eventData) {
76
- Object.entries(v.style).forEach(([key, value]) => {
77
- if (value !== "" && newValue.style) newValue.style[key] = value;
78
- });
79
- eventData.changeRecords?.forEach((record) => {
80
- if (record.propPath?.startsWith("style") && record.value === "") setValueByKeyPath(record.propPath, record.value, newValue);
81
- });
82
- } else newValue.style = { ...v.style };
83
71
  const historySource = eventData ? "props" : "code";
72
+ const replace = historySource === "code";
73
+ let newValue;
74
+ if (replace) if (source === "style") newValue = {
75
+ ...values.value,
76
+ id: v.id || values.value.id,
77
+ style: { ...v.style || {} }
78
+ };
79
+ else newValue = { ...v };
80
+ else {
81
+ newValue = {
82
+ ...v,
83
+ style: {}
84
+ };
85
+ if (v.style) {
86
+ Object.entries(v.style).forEach(([key, value]) => {
87
+ if (value !== "" && newValue.style) newValue.style[key] = value;
88
+ });
89
+ eventData?.changeRecords?.forEach((record) => {
90
+ if (record.propPath?.startsWith("style") && record.value === "") setValueByKeyPath(record.propPath, record.value, newValue);
91
+ });
92
+ }
93
+ }
84
94
  editorService.update(newValue, {
85
95
  changeRecords: eventData?.changeRecords,
86
96
  historySource,
97
+ replace,
87
98
  ...enablePropsFormValidate && error ? { invalidInfo: {
88
99
  id: newValue.id,
89
100
  source,
@@ -23,7 +23,7 @@ var ComponentListPanel_vue_vue_type_script_setup_true_lang_default = /*@__PURE__
23
23
  const stage = computed(() => editorService.get("stage"));
24
24
  const list = computed(() => componentListService.getList().map((group) => ({
25
25
  ...group,
26
- items: group.items.filter((item) => item.text.includes(searchText.value))
26
+ items: group.items.filter((item) => `${item.text || ""}${item.desc || ""}${item.type}`.toLocaleLowerCase().includes(searchText.value.toLocaleLowerCase()))
27
27
  })));
28
28
  const collapseValue = ref();
29
29
  watch(list, () => {
@@ -145,7 +145,8 @@ var Sidebar_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCo
145
145
  watch(() => props.data.status, (status) => {
146
146
  activeTabName.value = status || "0";
147
147
  });
148
- const { dragstartHandler, dragendHandler, floatBoxStates, showingBoxKeys } = useFloatBox(computed(() => sideBarItems.value.map((sideBarItem) => sideBarItem.$key)));
148
+ const slideKeys = computed(() => sideBarItems.value.map((sideBarItem) => sideBarItem.$key));
149
+ const { dragstartHandler, dragendHandler, floatBoxStates, showingBoxKeys } = useFloatBox(slideKeys);
149
150
  watch(() => showingBoxKeys.value.length, () => {
150
151
  if (!showingBoxKeys.value.some((key) => activeTabName.value === sideBarItems.value.find((v) => v.$key === key)?.text) && activeTabName.value) return;
151
152
  const nextSlideBarItem = sideBarItems.value.find((sideBarItem) => !showingBoxKeys.value.includes(sideBarItem.$key));
@@ -38,7 +38,8 @@ var DataSourceConfigPanel_vue_vue_type_script_setup_true_lang_default = /*@__PUR
38
38
  const initValues = ref({});
39
39
  const dataSourceConfig = ref([]);
40
40
  const { height: editorHeight } = useEditorContentHeight();
41
- const { boxPosition, calcBoxPosition } = useNextFloatBoxPosition(uiService, inject("parentFloating", ref(null)));
41
+ const parentFloating = inject("parentFloating", ref(null));
42
+ const { boxPosition, calcBoxPosition } = useNextFloatBoxPosition(uiService, parentFloating);
42
43
  const frameworkWidth = computed(() => uiService.get("frameworkRect")?.width || 0);
43
44
  /** 供「方法定义」tab 内的字段消费,用于打开数据源详情后自动打开指定方法 */
44
45
  provide("editingDataSourceMethodName", computed(() => props.editMethodName));
@@ -39,7 +39,7 @@ var LayerPanel_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defin
39
39
  let name = "";
40
40
  if (data.name) name = data.name;
41
41
  else if (data.items) name = "container";
42
- return `${data.id}${name}${data.type}`.includes(v);
42
+ return `${data.id}${name}${data.type || ""}`.toLocaleLowerCase().includes(v.toLocaleLowerCase());
43
43
  };
44
44
  const { filterTextChangeHandler } = useFilter(nodeData, nodeStatusMap, filterNodeMethod);
45
45
  const collapseAllHandler = () => {
@@ -51,7 +51,8 @@ var LayerPanel_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defin
51
51
  }
52
52
  };
53
53
  const { handleDragStart, handleDragEnd, handleDragLeave, handleDragOver } = useDrag(services, { canDropIn: (sourceIds, targetId) => props.canDropIn?.(sourceIds, targetId, "layer") });
54
- const { nodeClickHandler, nodeDblclickHandler, nodeContentMenuHandler, highlightHandler: mouseenterHandler } = useClick(services, isCtrlKeyDown, nodeStatusMap, useTemplateRef("menu"));
54
+ const menuRef = useTemplateRef("menu");
55
+ const { nodeClickHandler, nodeDblclickHandler, nodeContentMenuHandler, highlightHandler: mouseenterHandler } = useClick(services, isCtrlKeyDown, nodeStatusMap, menuRef);
55
56
  const dblclickHandler = async (event, data) => {
56
57
  if (props.beforeNodeDblclick) {
57
58
  if (await props.beforeNodeDblclick(event, data) === false) return;
@@ -141,7 +141,8 @@ var CodeBlock = class extends BaseService {
141
141
  * @returns {CodeBlockDSL}
142
142
  */
143
143
  getCodeDslByIds(ids) {
144
- return pick(this.getCodeDsl(), ids);
144
+ const codeDsl = this.getCodeDsl();
145
+ return pick(codeDsl, ids);
145
146
  }
146
147
  /**
147
148
  * 获取编辑状态
@@ -371,7 +372,8 @@ var CodeBlock = class extends BaseService {
371
372
  */
372
373
  async getUniqueId() {
373
374
  const newId = `code_${Math.random().toString(10).substring(2).substring(0, 4)}`;
374
- if (!keys(await this.getCodeDsl()).includes(newId)) return newId;
375
+ const dsl = await this.getCodeDsl();
376
+ if (!keys(dsl).includes(newId)) return newId;
375
377
  return await this.getUniqueId();
376
378
  }
377
379
  /**
@@ -467,14 +467,14 @@ var Editor = class extends BaseService {
467
467
  remove: removedPages
468
468
  });
469
469
  }
470
- async doUpdate(config, { changeRecords = [], historySource } = {}) {
470
+ async doUpdate(config, { changeRecords = [], historySource, replace = false } = {}) {
471
471
  if (!this.get("root")) throw new Error("root为空");
472
472
  if (!config?.id) throw new Error("没有配置或者配置缺少id值");
473
473
  const info = this.getNodeInfo(config.id, false);
474
474
  if (!info.node) throw new Error(`获取不到id为${config.id}的节点`);
475
475
  const node = toRaw(info.node);
476
- let newConfig = await toggleFixedPosition(toRaw(config), node, info.path, this.getLayout);
477
- newConfig = mergeWith(cloneDeep$1(node), newConfig, editorNodeMergeCustomizer);
476
+ let newConfig = replace ? cloneDeep$1(toRaw(config)) : await toggleFixedPosition(toRaw(config), node, info.path, this.getLayout);
477
+ if (!replace) newConfig = mergeWith(cloneDeep$1(node), newConfig, editorNodeMergeCustomizer);
478
478
  if (!newConfig.type) throw new Error("配置缺少type值");
479
479
  if (newConfig.type === NodeType.ROOT) {
480
480
  this.set("root", newConfig, { historySource });
@@ -489,9 +489,11 @@ var Editor = class extends BaseService {
489
489
  const parentNodeItems = parent.items;
490
490
  const index = getNodeIndex(newConfig.id, parent);
491
491
  if (!parentNodeItems || typeof index === "undefined" || index === -1) throw new Error("更新的节点未找到");
492
- const newLayout = await this.getLayout(newConfig);
493
- const layout = await this.getLayout(node);
494
- if (Array.isArray(newConfig.items) && newLayout !== layout) newConfig = setChildrenLayout(newConfig, newLayout);
492
+ if (!replace) {
493
+ const newLayout = await this.getLayout(newConfig);
494
+ const layout = await this.getLayout(node);
495
+ if (Array.isArray(newConfig.items) && newLayout !== layout) newConfig = setChildrenLayout(newConfig, newLayout);
496
+ }
495
497
  parentNodeItems[index] = newConfig;
496
498
  const selectedNodes = this.get("nodes");
497
499
  const targetIndex = selectedNodes.findIndex((nodeItem) => `${nodeItem.id}` === `${newConfig.id}`);
@@ -519,17 +521,19 @@ var Editor = class extends BaseService {
519
521
  * @param data.changeRecordList 多节点 form 端变更记录列表,按 config 数组同序对应每个节点;优先级高于 changeRecords
520
522
  * @param data.doNotPushHistory 是否不写入历史记录(默认 false)
521
523
  * @param data.historyDescription 入栈时附带的人类可读描述,用于历史面板展示(不影响 undo/redo 行为)
524
+ * @param data.replace 是否整节点替换:为 true 时跳过 mergeWith / toggleFixedPosition / setChildrenLayout,直接用传入配置覆盖(默认 false)
522
525
  * @returns 更新后的节点配置
523
526
  */
524
527
  async update(config, data = {}) {
525
528
  this.captureSelectionBeforeOp();
526
- const { doNotPushHistory = false, changeRecordList, changeRecords, historyDescription, historySource, invalidInfo } = data;
529
+ const { doNotPushHistory = false, changeRecordList, changeRecords, historyDescription, historySource, replace = false, invalidInfo } = data;
527
530
  const nodes = Array.isArray(config) ? config : [config];
528
531
  const updateData = await Promise.all(nodes.map((node, index) => {
529
532
  const recordsForNode = changeRecordList ? changeRecordList[index] ?? [] : changeRecords ?? [];
530
533
  return this.doUpdate(node, {
531
534
  changeRecords: recordsForNode,
532
- historySource
535
+ historySource,
536
+ replace
533
537
  });
534
538
  }));
535
539
  this.applyInvalidInfo(config, invalidInfo);
@@ -10,11 +10,17 @@ import serialize from "serialize-javascript";
10
10
  *
11
11
  * 全量收集与增量收集共用一个常驻 worker:增量收集调用频繁(每次节点更新都会触发),
12
12
  * 按次创建 worker 的启动开销无法接受,也容易漏掉销毁导致线程泄漏。
13
+ *
14
+ * 请求在主线程侧排队后逐个投递(worker 本身也是串行处理),这样 abort 时能直接丢掉尚未投递的请求,
15
+ * 无需销毁线程:worker 只在真正异常或销毁时才重建。
13
16
  */
14
17
  var CollectWorkerClient = class {
15
18
  worker = null;
16
19
  seed = 0;
17
- pending = /* @__PURE__ */ new Map();
20
+ /** 等待投递给 worker 的请求 */
21
+ queue = [];
22
+ /** 已投递、等待 worker 响应的请求,worker 串行处理,同一时刻最多一个 */
23
+ inflight = null;
18
24
  get isSupported() {
19
25
  return typeof Worker !== "undefined";
20
26
  }
@@ -44,34 +50,63 @@ var CollectWorkerClient = class {
44
50
  terminate() {
45
51
  this.worker?.terminate();
46
52
  this.worker = null;
47
- this.settleAllPending();
53
+ this.settleAll();
48
54
  }
49
55
  /**
50
- * 丢弃在途请求并重建 worker
51
- * clearIdleTasks / reset 中断收集时调用,避免已 abort 的长任务继续占着常驻 worker 拖慢后续收集
56
+ * 丢弃在途请求,但保留常驻 worker
57
+ *
58
+ * clearIdleTasks / reset 中断收集时调用。这里不能销毁 worker:worker 重建要重新加载并启动整份收集逻辑,
59
+ * 而 clearIdleTasks / reset 触发频繁(root 更新、数据源变更、历史回滚等),一旦下一次 abort 落在
60
+ * 上一个 worker 还没启动完的窗口内,就会陷入「加载中被销毁 → 重建 → 又被销毁」的循环,
61
+ * 表现为 worker 反复加载且依赖始终收集不完。
62
+ *
63
+ * 因此 abort 只做「不要这些结果」:尚未投递的请求直接丢掉,已投递的那一个标记为丢弃,
64
+ * 结果回来后忽略(不写回主线程),worker 继续复用。
52
65
  */
53
66
  abort() {
54
- this.terminate();
67
+ const { queue } = this;
68
+ this.queue = [];
69
+ for (const task of queue) task.resolve(null);
70
+ if (this.inflight && !this.inflight.discarded) {
71
+ this.inflight.discarded = true;
72
+ this.inflight.resolve(null);
73
+ }
55
74
  }
56
- /**
57
- * worker 按收到的顺序逐个处理请求,因此请求间不会互相打断,用 id 把结果分发回各自的调用方
58
- */
59
75
  request(createRequest) {
60
- const worker = this.getWorker();
61
- if (!worker) return Promise.resolve(null);
76
+ if (!this.isSupported) return Promise.resolve(null);
62
77
  this.seed += 1;
63
78
  const id = this.seed;
64
79
  return new Promise((resolve) => {
65
- this.pending.set(id, resolve);
66
- try {
67
- worker.postMessage(createRequest(id));
68
- } catch (e) {
69
- error("magic editor: 依赖收集 worker 通信失败", e);
70
- this.pending.delete(id);
71
- resolve(null);
72
- }
80
+ this.queue.push({
81
+ id,
82
+ createRequest,
83
+ resolve,
84
+ discarded: false
85
+ });
86
+ this.flush();
73
87
  });
74
88
  }
89
+ /**
90
+ * 投递队首请求,worker 串行处理,因此同一时刻只投递一个,用 id 把结果分发回各自的调用方
91
+ */
92
+ flush() {
93
+ if (this.inflight || !this.queue.length) return;
94
+ const worker = this.getWorker();
95
+ if (!worker) {
96
+ this.settleAll();
97
+ return;
98
+ }
99
+ const task = this.queue.shift();
100
+ this.inflight = task;
101
+ try {
102
+ worker.postMessage(task.createRequest(task.id));
103
+ } catch (e) {
104
+ error("magic editor: 依赖收集 worker 通信失败", e);
105
+ this.inflight = null;
106
+ if (!task.discarded) task.resolve(null);
107
+ this.flush();
108
+ }
109
+ }
75
110
  getWorker() {
76
111
  if (!this.isSupported) return null;
77
112
  if (this.worker) return this.worker;
@@ -94,20 +129,25 @@ var CollectWorkerClient = class {
94
129
  return this.worker;
95
130
  }
96
131
  handleResponse(response) {
97
- const resolve = this.pending.get(response?.id);
98
- if (!resolve) return;
99
- this.pending.delete(response.id);
100
- resolve(response.failed ? null : response);
132
+ const task = this.inflight;
133
+ if (task?.id !== response?.id) return;
134
+ this.inflight = null;
135
+ if (!task.discarded) task.resolve(response.failed ? null : response);
136
+ this.flush();
101
137
  }
102
138
  handleFatalError() {
103
139
  this.worker?.terminate();
104
140
  this.worker = null;
105
- this.settleAllPending();
141
+ this.settleAll();
106
142
  }
107
- settleAllPending() {
108
- const resolvers = [...this.pending.values()];
109
- this.pending.clear();
110
- for (const resolve of resolvers) resolve(null);
143
+ settleAll() {
144
+ const tasks = this.queue;
145
+ this.queue = [];
146
+ if (this.inflight) {
147
+ tasks.push(this.inflight);
148
+ this.inflight = null;
149
+ }
150
+ for (const task of tasks) if (!task.discarded) task.resolve(null);
111
151
  }
112
152
  };
113
153
  //#endregion