@tmagic/editor 1.8.0-manmanyu.8 → 1.8.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 (281) hide show
  1. package/dist/es/Editor.vue_vue_type_script_setup_true_lang.js +22 -13
  2. package/dist/es/components/CodeBlockEditor.vue_vue_type_script_setup_true_lang.js +10 -5
  3. package/dist/es/components/CodeParams.vue_vue_type_script_setup_true_lang.js +7 -6
  4. package/dist/es/components/CompareForm.vue_vue_type_script_setup_true_lang.js +21 -119
  5. package/dist/es/components/ContentMenu.vue_vue_type_script_setup_true_lang.js +21 -5
  6. package/dist/es/components/FloatingBox.vue_vue_type_script_setup_true_lang.js +62 -16
  7. package/dist/es/components/Icon.vue_vue_type_script_setup_true_lang.js +1 -1
  8. package/dist/es/components/Resizer.vue_vue_type_script_setup_true_lang.js +3 -2
  9. package/dist/es/components/ScrollBar.js +0 -1
  10. package/dist/es/components/ScrollBar.vue_vue_type_script_setup_true_lang.js +5 -4
  11. package/dist/es/components/ScrollViewer.vue_vue_type_script_setup_true_lang.js +1 -1
  12. package/dist/es/components/SearchInput.vue_vue_type_script_setup_true_lang.js +1 -1
  13. package/dist/es/components/SplitView.vue_vue_type_script_setup_true_lang.js +1 -1
  14. package/dist/es/components/ToolButton.vue_vue_type_script_setup_true_lang.js +1 -1
  15. package/dist/es/components/Tree.vue_vue_type_script_setup_true_lang.js +1 -1
  16. package/dist/es/components/TreeNode.vue_vue_type_script_setup_true_lang.js +1 -1
  17. package/dist/es/components/ViewForm.js +5 -0
  18. package/dist/es/components/ViewForm.vue_vue_type_script_setup_true_lang.js +56 -0
  19. package/dist/es/editorProps.js +7 -1
  20. package/dist/es/fields/Code.vue_vue_type_script_setup_true_lang.js +1 -1
  21. package/dist/es/fields/CodeLink.vue_vue_type_script_setup_true_lang.js +1 -1
  22. package/dist/es/fields/CodeSelect.vue_vue_type_script_setup_true_lang.js +30 -113
  23. package/dist/es/fields/CodeSelectCol.vue_vue_type_script_setup_true_lang.js +2 -2
  24. package/dist/es/fields/CondOpSelect.vue_vue_type_script_setup_true_lang.js +7 -19
  25. package/dist/es/fields/DataSourceFieldSelect/FieldSelect.vue_vue_type_script_setup_true_lang.js +7 -6
  26. package/dist/es/fields/DataSourceFieldSelect/Index.vue_vue_type_script_setup_true_lang.js +4 -2
  27. package/dist/es/fields/DataSourceFields.vue_vue_type_script_setup_true_lang.js +12 -4
  28. package/dist/es/fields/DataSourceInput.vue_vue_type_script_setup_true_lang.js +9 -20
  29. package/dist/es/fields/DataSourceMethodSelect.vue_vue_type_script_setup_true_name_true_lang.js +2 -2
  30. package/dist/es/fields/DataSourceMethods.vue_vue_type_script_setup_true_lang.js +5 -3
  31. package/dist/es/fields/DataSourceMocks.vue_vue_type_script_setup_true_lang.js +9 -4
  32. package/dist/es/fields/DataSourceSelect.vue_vue_type_script_setup_true_lang.js +2 -2
  33. package/dist/es/fields/DisplayConds.vue_vue_type_script_setup_true_lang.js +10 -110
  34. package/dist/es/fields/EventSelect.vue_vue_type_script_setup_true_lang.js +52 -363
  35. package/dist/es/fields/KeyValue.vue_vue_type_script_setup_true_lang.js +1 -1
  36. package/dist/es/fields/PageFragmentSelect.vue_vue_type_script_setup_true_lang.js +1 -1
  37. package/dist/es/fields/StyleSetter/Index.vue_vue_type_script_setup_true_lang.js +3 -6
  38. package/dist/es/fields/StyleSetter/components/BackgroundPosition.vue_vue_type_script_setup_true_lang.js +1 -1
  39. package/dist/es/fields/StyleSetter/components/Border.vue_vue_type_script_setup_true_lang.js +4 -35
  40. package/dist/es/fields/StyleSetter/components/Box.vue_vue_type_script_setup_true_lang.js +3 -3
  41. package/dist/es/fields/StyleSetter/configs.js +663 -0
  42. package/dist/es/fields/StyleSetter/icons/align-items/Center.js +1 -1
  43. package/dist/es/fields/StyleSetter/icons/align-items/FlexEnd.js +1 -1
  44. package/dist/es/fields/StyleSetter/icons/align-items/FlexStart.js +1 -1
  45. package/dist/es/fields/StyleSetter/icons/align-items/SpaceAround.js +1 -1
  46. package/dist/es/fields/StyleSetter/icons/align-items/SpaceBetween.js +1 -1
  47. package/dist/es/fields/StyleSetter/icons/background-repeat/NoRepeat.js +1 -1
  48. package/dist/es/fields/StyleSetter/icons/background-repeat/Repeat.js +1 -1
  49. package/dist/es/fields/StyleSetter/icons/background-repeat/RepeatX.js +1 -1
  50. package/dist/es/fields/StyleSetter/icons/background-repeat/RepeatY.js +1 -1
  51. package/dist/es/fields/StyleSetter/icons/display/Block.js +1 -1
  52. package/dist/es/fields/StyleSetter/icons/display/Flex.js +1 -1
  53. package/dist/es/fields/StyleSetter/icons/display/Inline.js +1 -1
  54. package/dist/es/fields/StyleSetter/icons/display/InlineBlock.js +1 -1
  55. package/dist/es/fields/StyleSetter/icons/display/None.js +1 -1
  56. package/dist/es/fields/StyleSetter/icons/flex-direction/Column.js +1 -1
  57. package/dist/es/fields/StyleSetter/icons/flex-direction/ColumnReverse.js +1 -1
  58. package/dist/es/fields/StyleSetter/icons/flex-direction/Row.js +1 -1
  59. package/dist/es/fields/StyleSetter/icons/flex-direction/RowReverse.js +1 -1
  60. package/dist/es/fields/StyleSetter/icons/justify-content/Center.js +1 -1
  61. package/dist/es/fields/StyleSetter/icons/justify-content/FlexEnd.js +1 -1
  62. package/dist/es/fields/StyleSetter/icons/justify-content/FlexStart.js +1 -1
  63. package/dist/es/fields/StyleSetter/icons/justify-content/SpaceAround.js +1 -1
  64. package/dist/es/fields/StyleSetter/icons/justify-content/SpaceBetween.js +1 -1
  65. package/dist/es/fields/StyleSetter/icons/text-align/Center.js +1 -1
  66. package/dist/es/fields/StyleSetter/icons/text-align/Left.js +1 -1
  67. package/dist/es/fields/StyleSetter/icons/text-align/Right.js +1 -1
  68. package/dist/es/fields/StyleSetter/pro/Background.vue_vue_type_script_setup_true_lang.js +29 -106
  69. package/dist/es/fields/StyleSetter/pro/Border.vue_vue_type_script_setup_true_lang.js +8 -11
  70. package/dist/es/fields/StyleSetter/pro/Font.vue_vue_type_script_setup_true_lang.js +30 -89
  71. package/dist/es/fields/StyleSetter/pro/Layout.vue_vue_type_script_setup_true_lang.js +29 -297
  72. package/dist/es/fields/StyleSetter/pro/Position.vue_vue_type_script_setup_true_lang.js +29 -82
  73. package/dist/es/fields/StyleSetter/pro/Transform.vue_vue_type_script_setup_true_lang.js +8 -24
  74. package/dist/es/fields/UISelect.js +0 -1
  75. package/dist/es/fields/UISelect.vue_vue_type_script_setup_true_lang.js +1 -1
  76. package/dist/es/fields/configs/codeSelect.js +98 -0
  77. package/dist/es/fields/configs/displayConds.js +158 -0
  78. package/dist/es/fields/configs/eventSelect.js +225 -0
  79. package/dist/es/fields/configs/stickyAddButton.js +21 -0
  80. package/dist/es/fields/headless-validation.js +139 -0
  81. package/dist/es/headless.js +2 -0
  82. package/dist/es/hooks/use-code-block-edit.js +4 -2
  83. package/dist/es/hooks/use-compare-form.js +101 -0
  84. package/dist/es/hooks/use-form-context.js +29 -0
  85. package/dist/es/hooks/use-stage.js +1 -0
  86. package/dist/es/icons/CenterIcon.vue_vue_type_script_setup_true_lang.js +1 -1
  87. package/dist/es/icons/CodeIcon.vue_vue_type_script_setup_true_lang.js +1 -1
  88. package/dist/es/icons/DatasourceIcon.js +1 -1
  89. package/dist/es/icons/FolderMinusIcon.vue_vue_type_script_setup_true_lang.js +1 -1
  90. package/dist/es/index.js +17 -9
  91. package/dist/es/initService.js +52 -16
  92. package/dist/es/layouts/AddPageBox.vue_vue_type_script_setup_true_lang.js +1 -1
  93. package/dist/es/layouts/CodeEditor.vue_vue_type_script_setup_true_lang.js +26 -10
  94. package/dist/es/layouts/Framework.vue_vue_type_script_setup_true_lang.js +11 -8
  95. package/dist/es/layouts/NavMenu.vue_vue_type_script_setup_true_lang.js +3 -3
  96. package/dist/es/layouts/NavMenuColumn.vue_vue_type_script_setup_true_lang.js +1 -1
  97. package/dist/es/layouts/history-list/Bucket.vue_vue_type_script_setup_true_lang.js +1 -1
  98. package/dist/es/layouts/history-list/BucketTab.vue_vue_type_script_setup_true_lang.js +8 -5
  99. package/dist/es/layouts/history-list/GroupRow.vue_vue_type_script_setup_true_lang.js +1 -1
  100. package/dist/es/layouts/history-list/HistoryDiffDialog.vue_vue_type_script_setup_true_lang.js +26 -10
  101. package/dist/es/layouts/history-list/HistoryListPanel.vue_vue_type_script_setup_true_lang.js +36 -28
  102. package/dist/es/layouts/history-list/InitialRow.vue_vue_type_script_setup_true_lang.js +1 -1
  103. package/dist/es/layouts/history-list/PageTab.vue_vue_type_script_setup_true_lang.js +1 -1
  104. package/dist/es/layouts/history-list/composables.js +1 -1
  105. package/dist/es/layouts/history-list/useHistoryList.js +4 -4
  106. package/dist/es/layouts/history-list/useHistoryRevert.js +38 -33
  107. package/dist/es/layouts/page-bar/AddButton.vue_vue_type_script_setup_true_lang.js +1 -1
  108. package/dist/es/layouts/page-bar/PageBar.vue_vue_type_script_setup_true_lang.js +1 -1
  109. package/dist/es/layouts/page-bar/PageBarScrollContainer.vue_vue_type_script_setup_true_lang.js +1 -1
  110. package/dist/es/layouts/page-bar/PageList.vue_vue_type_script_setup_true_lang.js +1 -1
  111. package/dist/es/layouts/page-bar/Search.vue_vue_type_script_setup_true_lang.js +2 -2
  112. package/dist/es/layouts/props-panel/FormPanel.vue_vue_type_script_setup_true_lang.js +50 -20
  113. package/dist/es/layouts/props-panel/PropsPanel.vue_vue_type_script_setup_true_lang.js +53 -35
  114. package/dist/es/layouts/props-panel/use-style-panel.js +3 -2
  115. package/dist/es/layouts/sidebar/ComponentListPanel.vue_vue_type_script_setup_true_lang.js +3 -3
  116. package/dist/es/layouts/sidebar/Sidebar.vue_vue_type_script_setup_true_lang.js +21 -36
  117. package/dist/es/layouts/sidebar/code-block/CodeBlockList.vue_vue_type_script_setup_true_lang.js +1 -1
  118. package/dist/es/layouts/sidebar/code-block/CodeBlockListPanel.vue_vue_type_script_setup_true_lang.js +4 -4
  119. package/dist/es/layouts/sidebar/code-block/useContentMenu.js +19 -4
  120. package/dist/es/layouts/sidebar/data-source/DataSourceAddButton.vue_vue_type_script_setup_true_lang.js +1 -1
  121. package/dist/es/layouts/sidebar/data-source/DataSourceConfigPanel.vue_vue_type_script_setup_true_lang.js +9 -4
  122. package/dist/es/layouts/sidebar/data-source/DataSourceList.vue_vue_type_script_setup_true_lang.js +1 -1
  123. package/dist/es/layouts/sidebar/data-source/DataSourceListPanel.vue_vue_type_script_setup_true_lang.js +4 -4
  124. package/dist/es/layouts/sidebar/data-source/useContentMenu.js +19 -4
  125. package/dist/es/layouts/sidebar/layer/LayerMenu.vue_vue_type_script_setup_true_lang.js +3 -3
  126. package/dist/es/layouts/sidebar/layer/LayerNodeContent.js +5 -0
  127. package/dist/es/layouts/sidebar/layer/LayerNodeContent.vue_vue_type_script_setup_true_lang.js +46 -0
  128. package/dist/es/layouts/sidebar/layer/LayerNodeTool.vue_vue_type_script_setup_true_lang.js +1 -1
  129. package/dist/es/layouts/sidebar/layer/LayerPanel.vue_vue_type_script_setup_true_lang.js +6 -4
  130. package/dist/es/layouts/sidebar/layer/use-click.js +3 -3
  131. package/dist/es/layouts/sidebar/layer/use-drag.js +11 -10
  132. package/dist/es/layouts/sidebar/layer/use-node-status.js +2 -2
  133. package/dist/es/layouts/workspace/Breadcrumb.vue_vue_type_script_setup_true_lang.js +1 -1
  134. package/dist/es/layouts/workspace/Workspace.vue_vue_type_script_setup_true_lang.js +1 -1
  135. package/dist/es/layouts/workspace/viewer/NodeListMenu.vue_vue_type_script_setup_true_lang.js +9 -3
  136. package/dist/es/layouts/workspace/viewer/Stage.vue_vue_type_script_setup_true_lang.js +55 -9
  137. package/dist/es/layouts/workspace/viewer/StageOverlay.vue_vue_type_script_setup_true_lang.js +1 -1
  138. package/dist/es/layouts/workspace/viewer/ViewerMenu.vue_vue_type_script_setup_true_lang.js +8 -8
  139. package/dist/es/plugin.js +35 -23
  140. package/dist/es/services/codeBlock.js +40 -31
  141. package/dist/es/services/dataSource.js +46 -34
  142. package/dist/es/services/dep.js +162 -41
  143. package/dist/es/services/editor.js +373 -137
  144. package/dist/es/services/events.js +4 -4
  145. package/dist/es/services/history.js +275 -392
  146. package/dist/es/services/keybinding.js +3 -3
  147. package/dist/es/services/props.js +2 -1
  148. package/dist/es/services/storage.js +2 -2
  149. package/dist/es/services/ui.js +7 -2
  150. package/dist/es/style.css +277 -114
  151. package/dist/es/utils/code-block.js +14 -7
  152. package/dist/es/utils/config.js +4 -1
  153. package/dist/es/utils/const.js +2 -2
  154. package/dist/es/utils/content-menu.js +2 -2
  155. package/dist/es/utils/data-source/index.js +34 -12
  156. package/dist/es/utils/dep/collect-worker-client.js +154 -0
  157. package/dist/es/utils/dep/idle-task.js +70 -22
  158. package/dist/es/utils/dep/worker.js +1 -1
  159. package/dist/es/utils/editor.js +4 -2
  160. package/dist/es/utils/event.js +135 -0
  161. package/dist/es/utils/history.js +35 -47
  162. package/dist/es/utils/monaco-editor.js +22 -6
  163. package/dist/es/utils/operator.js +2 -2
  164. package/dist/es/utils/props.js +50 -106
  165. package/dist/es/utils/type-match-rules.js +356 -0
  166. package/dist/style.css +277 -114
  167. package/dist/themes/magic-admin.css +978 -175
  168. package/dist/tmagic-editor-headless.umd.cjs +10880 -0
  169. package/dist/tmagic-editor.umd.cjs +13047 -11363
  170. package/package.json +18 -13
  171. package/src/Editor.vue +23 -6
  172. package/src/components/CodeBlockEditor.vue +3 -0
  173. package/src/components/CodeParams.vue +10 -4
  174. package/src/components/CompareForm.vue +20 -190
  175. package/src/components/ContentMenu.vue +34 -6
  176. package/src/components/FloatingBox.vue +71 -7
  177. package/src/components/ScrollBar.vue +0 -67
  178. package/src/components/ViewForm.vue +54 -0
  179. package/src/editorProps.ts +23 -10
  180. package/src/fields/Code.vue +1 -1
  181. package/src/fields/CodeSelect.vue +20 -113
  182. package/src/fields/CodeSelectCol.vue +1 -1
  183. package/src/fields/CondOpSelect.vue +5 -26
  184. package/src/fields/DataSourceFieldSelect/FieldSelect.vue +2 -2
  185. package/src/fields/DataSourceFieldSelect/Index.vue +4 -1
  186. package/src/fields/DataSourceFields.vue +5 -1
  187. package/src/fields/DataSourceInput.vue +10 -28
  188. package/src/fields/DataSourceMethodSelect.vue +1 -1
  189. package/src/fields/DataSourceMethods.vue +6 -2
  190. package/src/fields/DataSourceMocks.vue +3 -0
  191. package/src/fields/DataSourceSelect.vue +1 -1
  192. package/src/fields/DisplayConds.vue +17 -139
  193. package/src/fields/EventSelect.vue +29 -416
  194. package/src/fields/KeyValue.vue +1 -1
  195. package/src/fields/StyleSetter/Index.vue +2 -8
  196. package/src/fields/StyleSetter/components/Border.vue +4 -38
  197. package/src/fields/StyleSetter/components/Box.vue +1 -1
  198. package/src/fields/StyleSetter/components/Position.vue +1 -1
  199. package/src/fields/StyleSetter/configs.ts +690 -0
  200. package/src/fields/StyleSetter/pro/Background.vue +9 -64
  201. package/src/fields/StyleSetter/pro/Border.vue +5 -16
  202. package/src/fields/StyleSetter/pro/Font.vue +11 -71
  203. package/src/fields/StyleSetter/pro/Layout.vue +10 -230
  204. package/src/fields/StyleSetter/pro/Position.vue +11 -82
  205. package/src/fields/StyleSetter/pro/Transform.vue +6 -34
  206. package/src/fields/UISelect.vue +0 -12
  207. package/src/fields/configs/codeSelect.ts +127 -0
  208. package/src/fields/configs/displayConds.ts +184 -0
  209. package/src/fields/configs/eventSelect.ts +309 -0
  210. package/src/fields/configs/stickyAddButton.ts +32 -0
  211. package/src/fields/headless-validation.ts +177 -0
  212. package/src/headless.ts +33 -0
  213. package/src/hooks/index.ts +1 -0
  214. package/src/hooks/use-compare-form.ts +166 -0
  215. package/src/hooks/use-form-context.ts +56 -0
  216. package/src/hooks/use-stage.ts +1 -0
  217. package/src/index.ts +9 -0
  218. package/src/initService.ts +73 -18
  219. package/src/layouts/CodeEditor.vue +32 -6
  220. package/src/layouts/Framework.vue +7 -6
  221. package/src/layouts/history-list/BucketTab.vue +2 -2
  222. package/src/layouts/history-list/HistoryDiffDialog.vue +33 -15
  223. package/src/layouts/history-list/HistoryListPanel.vue +16 -18
  224. package/src/layouts/history-list/useHistoryRevert.ts +57 -41
  225. package/src/layouts/props-panel/FormPanel.vue +75 -20
  226. package/src/layouts/props-panel/PropsPanel.vue +81 -30
  227. package/src/layouts/props-panel/use-style-panel.ts +4 -3
  228. package/src/layouts/sidebar/ComponentListPanel.vue +6 -2
  229. package/src/layouts/sidebar/Sidebar.vue +5 -3
  230. package/src/layouts/sidebar/code-block/CodeBlockListPanel.vue +5 -2
  231. package/src/layouts/sidebar/code-block/useContentMenu.ts +14 -2
  232. package/src/layouts/sidebar/data-source/DataSourceConfigPanel.vue +3 -0
  233. package/src/layouts/sidebar/data-source/DataSourceListPanel.vue +3 -3
  234. package/src/layouts/sidebar/data-source/useContentMenu.ts +14 -2
  235. package/src/layouts/sidebar/layer/LayerMenu.vue +2 -2
  236. package/src/layouts/sidebar/layer/LayerNodeContent.vue +57 -0
  237. package/src/layouts/sidebar/layer/LayerPanel.vue +5 -2
  238. package/src/layouts/sidebar/layer/use-click.ts +3 -3
  239. package/src/layouts/sidebar/layer/use-node-status.ts +2 -2
  240. package/src/layouts/workspace/viewer/NodeListMenu.vue +4 -1
  241. package/src/layouts/workspace/viewer/Stage.vue +80 -10
  242. package/src/layouts/workspace/viewer/ViewerMenu.vue +7 -7
  243. package/src/plugin.ts +35 -25
  244. package/src/services/codeBlock.ts +4 -0
  245. package/src/services/dataSource.ts +3 -0
  246. package/src/services/dep.ts +292 -47
  247. package/src/services/editor.ts +383 -120
  248. package/src/services/events.ts +8 -7
  249. package/src/services/history.ts +22 -1
  250. package/src/services/keybinding.ts +3 -3
  251. package/src/services/ui.ts +26 -5
  252. package/src/theme/code-block.scss +0 -37
  253. package/src/theme/display-conds.scss +4 -0
  254. package/src/theme/event.scss +25 -33
  255. package/src/theme/floating-box.scss +9 -1
  256. package/src/theme/framework.scss +4 -1
  257. package/src/theme/layer-node-content.scss +14 -0
  258. package/src/theme/nav-menu.scss +5 -1
  259. package/src/theme/props-panel.scss +17 -3
  260. package/src/theme/scroll-bar.scss +64 -0
  261. package/src/theme/theme.scss +3 -0
  262. package/src/theme/themes/magic-admin/index.scss +109 -9
  263. package/src/theme/ui-select.scss +9 -0
  264. package/src/type.ts +216 -6
  265. package/src/utils/code-block.ts +1 -0
  266. package/src/utils/config.ts +9 -1
  267. package/src/utils/const.ts +3 -3
  268. package/src/utils/content-menu.ts +2 -2
  269. package/src/utils/data-source/index.ts +31 -12
  270. package/src/utils/dep/collect-worker-client.ts +215 -0
  271. package/src/utils/dep/idle-task.ts +104 -35
  272. package/src/utils/dep/worker.ts +113 -9
  273. package/src/utils/event.ts +237 -0
  274. package/src/utils/index.ts +2 -0
  275. package/src/utils/monaco-editor.ts +27 -0
  276. package/src/utils/operator.ts +2 -2
  277. package/src/utils/props.ts +61 -122
  278. package/src/utils/type-match-rules.ts +697 -0
  279. package/types/headless.d.ts +17 -0
  280. package/types/index.d.ts +1494 -978
  281. package/src/fields/StyleSetter/icons/align-items/index copy.ts +0 -5
@@ -59,6 +59,7 @@ const buildDiffPayload = (source: DiffPayloadSource, index: number, id?: string
59
59
  };
60
60
 
61
61
  interface MountedDiffDialog {
62
+ app: ReturnType<typeof createApp>;
62
63
  instance: {
63
64
  open: (_payload: DiffDialogPayload) => void;
64
65
  confirm: (_payload: DiffDialogPayload) => Promise<boolean>;
@@ -73,9 +74,9 @@ interface MountedDiffDialog {
73
74
  * 弹窗组件动态 import,避免拖累其它消费者。供「确认回滚」与「查看差异」两种交互共用。
74
75
  */
75
76
  const mountHistoryDiffDialog = async (
76
- options: Pick<UseHistoryRevertOptions, 'appContext' | 'extendState'> &
77
+ options: Pick<UseHistoryRevertOptions, 'appContext'> &
77
78
  CustomDiffFormOptions & {
78
- services: Pick<Services, 'editorService' | 'dataSourceService' | 'codeBlockService' | 'historyService'>;
79
+ services?: Services;
79
80
  isConfirm?: boolean;
80
81
  onClose?: () => void;
81
82
  },
@@ -89,9 +90,10 @@ const mountHistoryDiffDialog = async (
89
90
  const app = createApp(historyDiffDialog, {
90
91
  services: options.services,
91
92
  isConfirm: options.isConfirm,
92
- extendState: options.extendState,
93
93
  loadConfig: options.loadConfig,
94
94
  selfDiffFieldTypes: options.selfDiffFieldTypes,
95
+ width: options.width,
96
+ size: options.size ?? options.services?.uiService?.get('propsPanelSize'),
95
97
  onClose: options.onClose,
96
98
  });
97
99
  if (options.appContext) {
@@ -111,7 +113,7 @@ const mountHistoryDiffDialog = async (
111
113
  }, 300);
112
114
  };
113
115
 
114
- return { instance, destroy };
116
+ return { app, instance, destroy };
115
117
  };
116
118
 
117
119
  /**
@@ -121,9 +123,9 @@ const mountHistoryDiffDialog = async (
121
123
  */
122
124
  const confirmRevertWithDiffDialog = async (
123
125
  payload: DiffDialogPayload,
124
- options: Pick<UseHistoryRevertOptions, 'appContext' | 'extendState'> &
126
+ options: Pick<UseHistoryRevertOptions, 'appContext'> &
125
127
  CustomDiffFormOptions & {
126
- services: Pick<Services, 'editorService' | 'dataSourceService' | 'codeBlockService' | 'historyService'>;
128
+ services?: Services;
127
129
  },
128
130
  ): Promise<boolean> => {
129
131
  const { instance, destroy } = await mountHistoryDiffDialog({
@@ -143,9 +145,9 @@ const confirmRevertWithDiffDialog = async (
143
145
  */
144
146
  const viewHistoryDiffDialog = async (
145
147
  payload: DiffDialogPayload,
146
- options: Pick<UseHistoryRevertOptions, 'appContext' | 'extendState'> &
148
+ options: Pick<UseHistoryRevertOptions, 'appContext'> &
147
149
  CustomDiffFormOptions & {
148
- services: Pick<Services, 'editorService' | 'dataSourceService' | 'codeBlockService' | 'historyService'>;
150
+ services?: Services;
149
151
  },
150
152
  ): Promise<void> => {
151
153
  // onClose 在用户关闭弹窗时才触发,此时 handle.destroy 早已赋值。
@@ -182,19 +184,15 @@ const viewHistoryDiffDialog = async (
182
184
  * ```ts
183
185
  * import { useHistoryRevert } from '@tmagic/editor';
184
186
  *
185
- * const { onPageRevert, onPageDiff } = useHistoryRevert(editorRef.value); // editorRef.value 即 Editor 暴露的 services
187
+ * const { onPageRevert, onPageDiff } = useHistoryRevert({}, editorRef.value); // editorRef.value 即 Editor 暴露的 services
186
188
  * await onPageRevert(index); // 弹出差异 / 二次确认弹窗后回滚
187
189
  * onPageDiff(index); // 弹出只读差异弹窗查看前后值差异
188
190
  * ```
189
191
  */
190
- export const useHistoryRevert = (
191
- services: Pick<Services, 'editorService' | 'dataSourceService' | 'codeBlockService' | 'historyService'>,
192
- options: UseHistoryRevertOptions = {},
193
- ) => {
194
- const { editorService, dataSourceService, codeBlockService, historyService } = services;
192
+ export const useHistoryRevert = (options: UseHistoryRevertOptions = {}, services?: Services) => {
195
193
  // 自动捕获调用方所在组件的 appContext(在 setup 中调用时),业务方亦可显式覆盖。
196
194
  const appContext = options.appContext ?? getCurrentInstance()?.appContext ?? null;
197
- const { extendState } = options;
195
+ const { dialogWidth } = options;
198
196
 
199
197
  /** 目标数据已被删除、无法回滚时的统一提示。 */
200
198
  const showRevertTargetMissing = () => {
@@ -206,10 +204,7 @@ export const useHistoryRevert = (
206
204
  * 不弹差异弹窗,改用一个普通确认框替代「确定回滚」按钮,避免点击后无任何提示直接执行。
207
205
  * 用户取消时返回 false,调用方据此中止回滚。
208
206
  */
209
- const confirmRevert = (): Promise<boolean> =>
210
- confirmHistoryAction(
211
- '确定回滚该步骤吗?回滚会将该操作作为一条新记录反向应用(新增将被删除、删除将被还原),不影响后续历史记录。',
212
- );
207
+ const confirmRevert = (): Promise<boolean> => confirmHistoryAction('确定回滚该步骤吗?');
213
208
 
214
209
  /**
215
210
  * 「回滚」统一确认入口:可差异对比的步骤动态挂载 HistoryDiffDialog 走差异确认弹窗,
@@ -218,7 +213,13 @@ export const useHistoryRevert = (
218
213
  */
219
214
  const runRevert = (payload: DiffDialogPayload | null, extra?: CustomDiffFormOptions): Promise<boolean> => {
220
215
  if (payload) {
221
- return confirmRevertWithDiffDialog(payload, { appContext, extendState, services, ...extra });
216
+ return confirmRevertWithDiffDialog(payload, {
217
+ appContext,
218
+ services,
219
+ ...extra,
220
+ width: extra?.width ?? dialogWidth,
221
+ size: extra?.size,
222
+ });
222
223
  }
223
224
  return confirmRevert();
224
225
  };
@@ -227,8 +228,8 @@ export const useHistoryRevert = (
227
228
  buildDiffPayload(
228
229
  {
229
230
  category: 'node',
230
- groups: () => historyService.getHistoryGroups('page', editorService.get('page')?.id),
231
- getCurrent: (id) => editorService.getNodeById(id) as Record<string, any> | null,
231
+ groups: () => services?.historyService.getHistoryGroups('page', services?.editorService.get('page')?.id) ?? [],
232
+ getCurrent: (id) => services?.editorService.getNodeById(id) as Record<string, any> | null,
232
233
  resolveType: (n, o) => n.type || o.type || '',
233
234
  resolveLabel: (n, o) => n.name || o.name || n.type || o.type || '',
234
235
  },
@@ -239,8 +240,8 @@ export const useHistoryRevert = (
239
240
  buildDiffPayload(
240
241
  {
241
242
  category: 'data-source',
242
- groups: () => historyService.getHistoryGroups('dataSource'),
243
- getCurrent: (id) => dataSourceService.getDataSourceById(`${id}`) as Record<string, any> | null,
243
+ groups: () => services?.historyService.getHistoryGroups('dataSource') ?? [],
244
+ getCurrent: (id) => services?.dataSourceService.getDataSourceById(`${id}`) as Record<string, any> | null,
244
245
  resolveType: (n, o) => n.type || o.type || 'base',
245
246
  resolveLabel: (n, o, id) => n.title || o.title || `${id}`,
246
247
  },
@@ -252,8 +253,8 @@ export const useHistoryRevert = (
252
253
  buildDiffPayload(
253
254
  {
254
255
  category: 'code-block',
255
- groups: () => historyService.getHistoryGroups('codeBlock'),
256
- getCurrent: (id) => codeBlockService.getCodeContentById(id) as Record<string, any> | null,
256
+ groups: () => services?.historyService.getHistoryGroups('codeBlock') ?? [],
257
+ getCurrent: (id) => services?.codeBlockService.getCodeContentById(id) as Record<string, any> | null,
257
258
  resolveLabel: (n, o, id) => n.name || o.name || `${id}`,
258
259
  },
259
260
  index,
@@ -267,17 +268,17 @@ export const useHistoryRevert = (
267
268
  * add(回滚即删除)即使目标已不在,也已达成「删除」目的,不视为失败。
268
269
  */
269
270
  const isPageRevertTargetMissing = (index: number): boolean => {
270
- const step = historyService.getStepList('page', editorService.get('page')?.id)[index]?.step;
271
+ const step = services?.historyService.getStepList('page', services?.editorService.get('page')?.id)[index]?.step;
271
272
  if (!step) return false;
272
273
  if (step.opType === 'update') {
273
274
  return (step.diff ?? []).some((item) => {
274
275
  const id = item.newSchema?.id ?? item.oldSchema?.id;
275
- return id !== undefined && !editorService.getNodeById(id, false);
276
+ return id !== undefined && !services?.editorService.getNodeById(id, false);
276
277
  });
277
278
  }
278
279
  if (step.opType === 'remove') {
279
280
  return (step.diff ?? []).some(
280
- (item) => item.parentId !== undefined && !editorService.getNodeById(item.parentId, false),
281
+ (item) => item.parentId !== undefined && !services?.editorService.getNodeById(item.parentId, false),
281
282
  );
282
283
  }
283
284
  return false;
@@ -285,14 +286,14 @@ export const useHistoryRevert = (
285
286
 
286
287
  /** 数据源 update 步骤回滚时,对应数据源必须仍存在(已删除则无处写回旧值)。 */
287
288
  const isDataSourceRevertTargetMissing = (id: string | number, index: number): boolean => {
288
- const step = historyService.getStepList('dataSource', id)[index]?.step;
289
- return Boolean(step?.opType === 'update' && !dataSourceService.getDataSourceById(`${id}`));
289
+ const step = services?.historyService.getStepList('dataSource', id)[index]?.step;
290
+ return Boolean(step?.opType === 'update' && !services?.dataSourceService.getDataSourceById(`${id}`));
290
291
  };
291
292
 
292
293
  /** 代码块 update 步骤回滚时,对应代码块必须仍存在(已删除则无处写回旧值)。 */
293
294
  const isCodeBlockRevertTargetMissing = (id: string | number, index: number): boolean => {
294
- const step = historyService.getStepList('codeBlock', id)[index]?.step;
295
- return Boolean(step?.opType === 'update' && !codeBlockService.getCodeContentById(id));
295
+ const step = services?.historyService.getStepList('codeBlock', id)[index]?.step;
296
+ return Boolean(step?.opType === 'update' && !services?.codeBlockService.getCodeContentById(id));
296
297
  };
297
298
 
298
299
  const onPageRevert = (index: number) => {
@@ -300,8 +301,8 @@ export const useHistoryRevert = (
300
301
  showRevertTargetMissing();
301
302
  return Promise.resolve(null);
302
303
  }
303
- return runRevert(buildPageDiffPayload(index)).then((result) =>
304
- result ? editorService.revertPageStep(index) : null,
304
+ return runRevert(buildPageDiffPayload(index), {}).then((result) =>
305
+ result ? services?.editorService.revertPageStep(index) : null,
305
306
  );
306
307
  };
307
308
 
@@ -311,7 +312,7 @@ export const useHistoryRevert = (
311
312
  return Promise.resolve(null);
312
313
  }
313
314
  return runRevert(buildDataSourceDiffPayload(id, index)).then((result) =>
314
- result ? dataSourceService.revert(id, index) : null,
315
+ result ? services?.dataSourceService.revert(id, index) : null,
315
316
  );
316
317
  };
317
318
 
@@ -321,7 +322,7 @@ export const useHistoryRevert = (
321
322
  return Promise.resolve(null);
322
323
  }
323
324
  return runRevert(buildCodeBlockDiffPayload(id, index)).then((result) =>
324
- result ? codeBlockService.revert(id, index) : null,
325
+ result ? services?.codeBlockService.revert(id, index) : null,
325
326
  );
326
327
  };
327
328
 
@@ -331,17 +332,23 @@ export const useHistoryRevert = (
331
332
  */
332
333
  const onPageDiff = (index: number): Promise<void> | void => {
333
334
  const payload = buildPageDiffPayload(index);
334
- if (payload) return viewHistoryDiffDialog(payload, { appContext, extendState, services });
335
+ if (payload) {
336
+ return viewHistoryDiffDialog(payload, {
337
+ appContext,
338
+ services,
339
+ width: dialogWidth,
340
+ });
341
+ }
335
342
  };
336
343
 
337
344
  const onDataSourceDiff = (id: string | number, index: number): Promise<void> | void => {
338
345
  const payload = buildDataSourceDiffPayload(id, index);
339
- if (payload) return viewHistoryDiffDialog(payload, { appContext, extendState, services });
346
+ if (payload) return viewHistoryDiffDialog(payload, { appContext, services, width: dialogWidth });
340
347
  };
341
348
 
342
349
  const onCodeBlockDiff = (id: string | number, index: number): Promise<void> | void => {
343
350
  const payload = buildCodeBlockDiffPayload(id, index);
344
- if (payload) return viewHistoryDiffDialog(payload, { appContext, extendState, services });
351
+ if (payload) return viewHistoryDiffDialog(payload, { appContext, services, width: dialogWidth });
345
352
  };
346
353
 
347
354
  /**
@@ -368,6 +375,8 @@ export const useHistoryRevert = (
368
375
  const confirmed = await runRevert(revertOptions.diffPayload ?? null, {
369
376
  loadConfig: revertOptions.loadConfig,
370
377
  selfDiffFieldTypes: revertOptions.selfDiffFieldTypes,
378
+ width: revertOptions.width,
379
+ size: revertOptions.size,
371
380
  });
372
381
  if (!confirmed) return null;
373
382
  return await revertOptions.revert();
@@ -378,7 +387,14 @@ export const useHistoryRevert = (
378
387
  * 可透传 `loadConfig` / `selfDiffFieldTypes`。payload 为 null(不可对比)时静默返回。
379
388
  */
380
389
  const viewDiff = (payload: DiffDialogPayload | null, extra?: CustomDiffFormOptions): Promise<void> | void => {
381
- if (payload) return viewHistoryDiffDialog(payload, { appContext, extendState, services, ...extra });
390
+ if (payload)
391
+ return viewHistoryDiffDialog(payload, {
392
+ appContext,
393
+ services,
394
+ ...extra,
395
+ width: extra?.width ?? dialogWidth,
396
+ size: extra?.size,
397
+ });
382
398
  };
383
399
 
384
400
  return {
@@ -12,7 +12,9 @@
12
12
  :size="propsPanelSize"
13
13
  :init-values="values"
14
14
  :config="config"
15
- :extend-state="extendState"
15
+ :type-match-valid="true"
16
+ :context="formContext"
17
+ :validate-on-init="true"
16
18
  @change="submit"
17
19
  @error="errorHandler"
18
20
  ></MForm>
@@ -43,15 +45,18 @@
43
45
  </template>
44
46
 
45
47
  <script setup lang="ts">
46
- import { computed, getCurrentInstance, inject, onMounted, onUnmounted, ref, useTemplateRef, watchEffect } from 'vue';
48
+ import { computed, getCurrentInstance, inject, onMounted, onUnmounted, ref, useTemplateRef } from 'vue';
47
49
  import { Document as DocumentIcon } from '@element-plus/icons-vue';
48
50
 
49
- import { TMagicButton, TMagicScrollbar } from '@tmagic/design';
50
- import type { ContainerChangeEventData, FormConfig, FormState, FormValue } from '@tmagic/form';
51
- import { MForm } from '@tmagic/form';
51
+ import { TMagicButton, tMagicMessage, TMagicScrollbar } from '@tmagic/design';
52
+ import type { ContainerChangeEventData, FormConfig, FormValue } from '@tmagic/form';
53
+ import { MForm, validateForm } from '@tmagic/form';
54
+ import { filterXSS } from '@tmagic/utils';
52
55
 
53
56
  import MIcon from '@editor/components/Icon.vue';
57
+ import { ENABLE_PROPS_FORM_VALIDATE } from '@editor/editorProps';
54
58
  import { useEditorContentHeight } from '@editor/hooks/use-editor-content-height';
59
+ import { useEditorFormContext } from '@editor/hooks/use-form-context';
55
60
  import { useServices } from '@editor/hooks/use-services';
56
61
 
57
62
  import CodeEditor from '../CodeEditor.vue';
@@ -70,36 +75,31 @@ const props = defineProps<{
70
75
  disabledShowSrc?: boolean;
71
76
  labelWidth?: string;
72
77
  codeValueKey?: string;
73
- labelPosition?: string;
74
- extendState?: (_state: FormState) => Record<string, any> | Promise<Record<string, any>>;
78
+ labelPosition?: 'top' | 'left' | 'right';
75
79
  }>();
76
80
 
77
81
  const emit = defineEmits<{
78
- submit: [values: any, eventData?: ContainerChangeEventData];
82
+ submit: [values: any, eventData?: ContainerChangeEventData, error?: any];
79
83
  'submit-error': [e: any];
80
84
  'form-error': [e: any];
81
85
  mounted: [internalInstance: any];
82
86
  unmounted: [];
83
87
  }>();
84
88
 
89
+ const enablePropsFormValidate = inject(ENABLE_PROPS_FORM_VALIDATE, false);
90
+
85
91
  const services = useServices();
86
- const { editorService, uiService } = services;
92
+ const { uiService } = services;
87
93
 
88
94
  const codeOptions = inject('codeOptions', {});
89
95
 
90
96
  const showSrc = ref(false);
91
97
  const propsPanelSize = computed(() => uiService.get('propsPanelSize') || 'small');
92
98
  const { height: editorContentHeight } = useEditorContentHeight();
93
- const stage = computed(() => editorService.get('stage'));
94
99
 
95
- const configFormRef = useTemplateRef<InstanceType<typeof MForm>>('configForm');
100
+ const formContext = useEditorFormContext(() => services);
96
101
 
97
- watchEffect(() => {
98
- if (configFormRef.value) {
99
- configFormRef.value.formState.stage = stage.value;
100
- configFormRef.value.formState.services = services;
101
- }
102
- });
102
+ const configFormRef = useTemplateRef<InstanceType<typeof MForm>>('configForm');
103
103
 
104
104
  const internalInstance = getCurrentInstance();
105
105
  onMounted(() => {
@@ -113,9 +113,16 @@ onUnmounted(() => {
113
113
  const submit = async (v: FormValue, eventData: ContainerChangeEventData) => {
114
114
  try {
115
115
  const values = await configFormRef.value?.submitForm();
116
+ // 校验成功:正常更新节点(第三个参数 error 为空,表示清除该来源的错误记录)
116
117
  emit('submit', values, eventData);
117
118
  } catch (e: any) {
118
- emit('submit-error', e);
119
+ if (enablePropsFormValidate) {
120
+ // 启用校验联动:校验失败时仍以当前表单值更新节点,并把错误信息一并抛给上层记录
121
+ emit('submit', v, eventData, e);
122
+ } else {
123
+ // 未启用:保持原行为,校验失败丢弃本次改动
124
+ emit('submit-error', e);
125
+ }
119
126
  }
120
127
  };
121
128
 
@@ -123,8 +130,56 @@ const errorHandler = (e: any) => {
123
130
  emit('form-error', e);
124
131
  };
125
132
 
126
- const saveCode = (values: any) => {
127
- emit('submit', props.codeValueKey ? { [props.codeValueKey]: values } : values);
133
+ /**
134
+ * 将校验错误文案安全地转为用于弹窗展示的 HTML。
135
+ *
136
+ * 文案形如 `字段 -> 主文案\n\n建议`,多条以结构性 `<br>` 拼接。为在保留换行排版的同时
137
+ * 避免 `${value}`/字段名中可能夹带的 HTML 造成 XSS:先按结构性 `<br>` 拆分,对每段做 HTML
138
+ * 转义后再把段内换行 `\n` 替换为 `<br>`,最后用 `<br>` 拼回。
139
+ */
140
+ const formatValidateErrorHtml = (error: string): string =>
141
+ error
142
+ .split(/<br\s*\/?>/i)
143
+ .map((segment) => filterXSS(segment).replaceAll('\n', '<br>'))
144
+ .join('<br>');
145
+
146
+ const saveCode = async (values: any) => {
147
+ const newValues = props.codeValueKey ? { [props.codeValueKey]: values } : values;
148
+
149
+ if (!enablePropsFormValidate) {
150
+ // 未启用校验联动:保持原行为,直接提交源码保存的值
151
+ emit('submit', newValues);
152
+ return;
153
+ }
154
+
155
+ // 启用校验联动:源码编辑器保存的值未经过表单交互,这里对最新配置做一次无渲染的静默校验
156
+ // (不挂载任何组件,也不影响页面上正在展示的表单),并将校验结果(错误信息)随提交
157
+ // 一并抛给上层记录,使源码保存的错误状态与表单编辑保持一致。
158
+ //
159
+ // 配置里的 display / rules 回调会从 formState 上读 services,因此必须带上 context。
160
+ try {
161
+ const error = await validateForm({
162
+ config: props.config,
163
+ typeMatchValid: true,
164
+ initValues: newValues,
165
+ context: formContext.value,
166
+ });
167
+
168
+ if (error) {
169
+ tMagicMessage({
170
+ type: 'error',
171
+ message: formatValidateErrorHtml(error),
172
+ dangerouslyUseHTMLString: true,
173
+ });
174
+ }
175
+
176
+ emit('submit', newValues, undefined, error ? new Error(error) : undefined);
177
+ } catch (e: any) {
178
+ console.error('validateForm error', e);
179
+ // 嵌套配置 / initValue 等机制故障不得当成「校验通过」,
180
+ // 把 error 交给上层记录,同时仍提交源码,避免阻塞保存。
181
+ emit('submit', newValues, undefined, e instanceof Error ? e : new Error(String(e)));
182
+ }
128
183
  };
129
184
 
130
185
  defineExpose({ configForm: configFormRef, submit });
@@ -8,8 +8,7 @@
8
8
  :config="curFormConfig"
9
9
  :values="values"
10
10
  :disabledShowSrc="disabledShowSrc"
11
- :extendState="extendState"
12
- @submit="submit"
11
+ @submit="(v, eventData, error) => submit(v, eventData, error, 'props')"
13
12
  @submit-error="errorHandler"
14
13
  @form-error="errorHandler"
15
14
  @mounted="mountedHandler"
@@ -26,8 +25,7 @@
26
25
  :config="styleFormConfig"
27
26
  :values="values"
28
27
  :disabledShowSrc="disabledShowSrc"
29
- :extendState="extendState"
30
- @submit="submit"
28
+ @submit="(v, eventData, error) => submit(v, eventData, error, 'style')"
31
29
  @submit-error="errorHandler"
32
30
  @form-error="errorHandler"
33
31
  >
@@ -55,20 +53,21 @@
55
53
  </template>
56
54
 
57
55
  <script lang="ts" setup>
58
- import { computed, onBeforeUnmount, onMounted, ref, useTemplateRef, watch, watchEffect } from 'vue';
56
+ import { computed, inject, onBeforeUnmount, onMounted, ref, useTemplateRef, watch, watchEffect } from 'vue';
59
57
  import { Close, Sugar } from '@element-plus/icons-vue';
60
58
  import type { OnDrag } from 'gesto';
61
59
 
62
60
  import { type MNode } from '@tmagic/core';
63
61
  import { TMagicButton } from '@tmagic/design';
64
- import type { ContainerChangeEventData, FormState, FormValue } from '@tmagic/form';
62
+ import type { ContainerChangeEventData, FormValue } from '@tmagic/form';
65
63
  import { setValueByKeyPath } from '@tmagic/utils';
66
64
 
67
65
  import MIcon from '@editor/components/Icon.vue';
68
66
  import Resizer from '@editor/components/Resizer.vue';
67
+ import { ENABLE_PROPS_FORM_VALIDATE } from '@editor/editorProps';
69
68
  import { useServices } from '@editor/hooks/use-services';
70
69
  import { Protocol } from '@editor/services/storage';
71
- import type { PropsPanelSlots } from '@editor/type';
70
+ import type { NodeInvalidSource, PropsPanelSlots } from '@editor/type';
72
71
  import { styleTabConfig } from '@editor/utils';
73
72
  import { PROPS_PANEL_WIDTH_STORAGE_KEY } from '@editor/utils/const';
74
73
 
@@ -83,7 +82,6 @@ defineOptions({
83
82
 
84
83
  defineProps<{
85
84
  disabledShowSrc?: boolean;
86
- extendState?: (_state: FormState) => Record<string, any> | Promise<Record<string, any>>;
87
85
  }>();
88
86
 
89
87
  const emit = defineEmits<{
@@ -95,6 +93,8 @@ const emit = defineEmits<{
95
93
 
96
94
  const { editorService, uiService, propsService, storageService } = useServices();
97
95
 
96
+ const enablePropsFormValidate = inject(ENABLE_PROPS_FORM_VALIDATE, false);
97
+
98
98
  const values = ref<FormValue>({});
99
99
  // ts类型应该是FormConfig, 但是打包时会出错,所以暂时用any
100
100
  const curFormConfig = ref<any>([]);
@@ -108,14 +108,31 @@ const styleFormConfig = [
108
108
  },
109
109
  ];
110
110
 
111
+ // 用单调递增序号标记每次 init 调用,只让"最新一次"的 await 结果落到 ref 上。
112
+ // 避免节点快速切换时多个 init 并发 + 解析顺序错乱导致 stale config 覆盖最新选中节点,
113
+ // 以及组件已卸载 / FormPanel 正在 remount 的中间态下写 ref 触发 Vue setRef 把 __vnode
114
+ // 设到 null 上的报错(TypeError: Cannot set properties of null (setting '__vnode'))。
115
+ let initSeq = 0;
116
+ let mounted = true;
117
+
111
118
  const init = async () => {
119
+ initSeq += 1;
120
+ const seq = initSeq;
121
+
112
122
  if (!node.value) {
123
+ if (seq !== initSeq || !mounted) return;
113
124
  curFormConfig.value = [];
114
125
  return;
115
126
  }
116
127
 
117
128
  const type = node.value.type || (node.value.items ? 'container' : 'text');
118
- curFormConfig.value = await propsService.getPropsConfig(type, { node: node.value });
129
+ const config = await propsService.getPropsConfig(type, { node: node.value });
130
+
131
+ // 期间被新一次 init 取代 / 组件已卸载,丢弃本次结果
132
+ if (seq !== initSeq || !mounted) return;
133
+ if (!node.value) return;
134
+
135
+ curFormConfig.value = config;
119
136
  values.value = node.value;
120
137
  };
121
138
 
@@ -123,39 +140,73 @@ watchEffect(init);
123
140
  propsService.on('props-configs-change', init);
124
141
 
125
142
  onBeforeUnmount(() => {
143
+ mounted = false;
126
144
  propsService.off('props-configs-change', init);
127
145
  });
128
146
 
129
- const submit = async (v: MNode, eventData?: ContainerChangeEventData) => {
147
+ const submit = async (
148
+ v: MNode,
149
+ eventData?: ContainerChangeEventData,
150
+ error?: any,
151
+ source: NodeInvalidSource = 'props',
152
+ ) => {
130
153
  try {
131
154
  if (!v.id) {
132
155
  v.id = values.value.id;
133
156
  }
134
157
 
135
- const newValue: MNode = {
136
- ...v,
137
- style: {},
138
- };
139
-
140
- if (v.style) {
141
- Object.entries(v.style).forEach(([key, value]) => {
142
- if (value !== '' && newValue.style) {
143
- newValue.style[key] = value;
144
- }
145
- });
146
-
147
- eventData?.changeRecords?.forEach((record) => {
148
- if (record.propPath?.startsWith('style') && record.value === '') {
149
- setValueByKeyPath(record.propPath, record.value, newValue);
150
- }
151
- });
152
- }
153
-
154
158
  // 区分操作途径:表单字段编辑(MForm @change)会带上 eventData(含 changeRecords);
155
159
  // 源码编辑器(CodeEditor @save → saveCode)保存时不带 eventData,据此标记为「源码编辑器」。
156
160
  const historySource = eventData ? 'props' : 'code';
161
+ // 源码编辑统一走整节点 replace,避免 merge 保留已删除字段。
162
+ const replace = historySource === 'code';
163
+
164
+ let newValue: MNode;
165
+
166
+ if (replace) {
167
+ if (source === 'style') {
168
+ // 样式面板源码仅提交 { style }:先把新 style 替换到原节点上,再整节点覆盖。
169
+ newValue = {
170
+ ...values.value,
171
+ id: v.id || values.value.id,
172
+ style: { ...(v.style || {}) },
173
+ };
174
+ } else {
175
+ // 属性面板源码提交完整节点 DSL
176
+ newValue = { ...v };
177
+ }
178
+ } else {
179
+ newValue = {
180
+ ...v,
181
+ style: {},
182
+ };
183
+
184
+ if (v.style) {
185
+ // 空字符串样式值表示「清除该样式」,需保留才能在 doUpdate 的 mergeWith 中覆盖旧值。
186
+ // 表单编辑:先过滤掉空字符串(避免表单默认空值污染 DSL),
187
+ // 再按 changeRecords 恢复被主动清空的字段。
188
+ Object.entries(v.style).forEach(([key, value]) => {
189
+ if (value !== '' && newValue.style) {
190
+ newValue.style[key] = value;
191
+ }
192
+ });
193
+
194
+ eventData?.changeRecords?.forEach((record) => {
195
+ if (record.propPath?.startsWith('style') && record.value === '') {
196
+ setValueByKeyPath(record.propPath, record.value, newValue);
197
+ }
198
+ });
199
+ }
200
+ }
157
201
 
158
- editorService.update(newValue, { changeRecords: eventData?.changeRecords, historySource });
202
+ editorService.update(newValue, {
203
+ changeRecords: eventData?.changeRecords,
204
+ historySource,
205
+ replace,
206
+ // 启用校验联动时,仅校验失败(error 存在)才把错误信息随更新传入 editorService 记录;
207
+ // 其余情况(含表单校验成功、CodeEditor 源码保存)不携带 invalidInfo,由 editorService 在执行 update 时统一清除该节点错误。
208
+ ...(enablePropsFormValidate && error ? { invalidInfo: { id: newValue.id, source, error: error?.message } } : {}),
209
+ });
159
210
  } catch (e: any) {
160
211
  emit('submit-error', e);
161
212
  }
@@ -2,7 +2,7 @@ import { computed, type Ref, watch } from 'vue';
2
2
 
3
3
  import { Protocol } from '@editor/services/storage';
4
4
  import { Services } from '@editor/type';
5
- import { MIN_CENTER_COLUMN_WIDTH, RIGHT_COLUMN_WIDTH_STORAGE_KEY } from '@editor/utils/const';
5
+ import { RIGHT_COLUMN_WIDTH_STORAGE_KEY } from '@editor/utils/const';
6
6
 
7
7
  export const useStylePanel = (
8
8
  { uiService, storageService }: Pick<Services, 'uiService' | 'storageService'>,
@@ -47,8 +47,9 @@ export const useStylePanel = (
47
47
  }
48
48
 
49
49
  if (columnWidth.center < 0) {
50
- columnWidth.right = columnWidth.right + columnWidth.center - MIN_CENTER_COLUMN_WIDTH;
51
- columnWidth.center = MIN_CENTER_COLUMN_WIDTH;
50
+ const minCenterColumnWidth = uiService.get('minCenterColumnWidth');
51
+ columnWidth.right = columnWidth.right + columnWidth.center - minCenterColumnWidth;
52
+ columnWidth.center = minCenterColumnWidth;
52
53
 
53
54
  propsPanelWidth.value = columnWidth.right / 2;
54
55
  }
@@ -71,7 +71,11 @@ const stage = computed(() => editorService.get('stage'));
71
71
  const list = computed<ComponentGroup[]>(() =>
72
72
  componentListService.getList().map((group: ComponentGroup) => ({
73
73
  ...group,
74
- items: group.items.filter((item: ComponentItem) => item.text.includes(searchText.value)),
74
+ items: group.items.filter((item: ComponentItem) =>
75
+ `${item.text || ''}${item.desc || ''}${item.type}`
76
+ .toLocaleLowerCase()
77
+ .includes(searchText.value.toLocaleLowerCase()),
78
+ ),
75
79
  })),
76
80
  );
77
81
 
@@ -145,6 +149,6 @@ const dragHandler = (e: DragEvent) => {
145
149
 
146
150
  if (timeout || !stage.value) return;
147
151
 
148
- timeout = stage.value.delayedMarkContainer(e);
152
+ timeout = stage.value.delayedMarkContainer(e, [], true);
149
153
  };
150
154
  </script>