@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
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.8.0-manmanyu.8",
2
+ "version": "1.8.0",
3
3
  "name": "@tmagic/editor",
4
4
  "type": "module",
5
5
  "sideEffects": [
@@ -17,6 +17,11 @@
17
17
  "import": "./dist/es/index.js",
18
18
  "require": "./dist/tmagic-editor.umd.cjs"
19
19
  },
20
+ "./headless": {
21
+ "types": "./types/headless.d.ts",
22
+ "import": "./dist/es/headless.js",
23
+ "require": "./dist/tmagic-editor-headless.umd.cjs"
24
+ },
20
25
  "./dist/style.css": {
21
26
  "import": "./dist/style.css",
22
27
  "require": "./dist/style.css"
@@ -54,29 +59,29 @@
54
59
  "events": "^3.3.0",
55
60
  "gesto": "^1.19.4",
56
61
  "keycon": "^1.4.0",
57
- "lodash-es": "^4.17.21",
62
+ "lodash-es": "^4.18.1",
58
63
  "moveable": "^0.53.0",
59
- "serialize-javascript": "^7.0.0",
60
- "sortablejs": "^1.15.6",
61
- "@tmagic/design": "1.8.0-manmanyu.8",
62
- "@tmagic/form": "1.8.0-manmanyu.8",
63
- "@tmagic/utils": "1.8.0-manmanyu.8",
64
- "@tmagic/table": "1.8.0-manmanyu.8",
65
- "@tmagic/stage": "1.8.0-manmanyu.8"
64
+ "serialize-javascript": "^7.1.1",
65
+ "sortablejs": "^1.15.7",
66
+ "@tmagic/design": "1.8.0",
67
+ "@tmagic/form": "1.8.0",
68
+ "@tmagic/stage": "1.8.0",
69
+ "@tmagic/utils": "1.8.0",
70
+ "@tmagic/table": "1.8.0"
66
71
  },
67
72
  "devDependencies": {
68
73
  "@types/events": "^3.0.3",
69
- "@types/lodash-es": "^4.17.4",
74
+ "@types/lodash-es": "^4.17.12",
70
75
  "@types/serialize-javascript": "^5.0.4",
71
76
  "@types/sortablejs": "^1.15.9",
72
- "@vue/test-utils": "^2.4.6"
77
+ "@vue/test-utils": "^2.5.1"
73
78
  },
74
79
  "peerDependencies": {
75
80
  "monaco-editor": "^0.55.1 ",
76
81
  "type-fest": "^5.2.0",
77
82
  "typescript": "^6.0.3",
78
- "vue": "^3.5.34",
79
- "@tmagic/core": "1.8.0-manmanyu.8"
83
+ "vue": "^3.5.43",
84
+ "@tmagic/core": "1.8.0"
80
85
  },
81
86
  "peerDependenciesMeta": {
82
87
  "typescript": {
package/src/Editor.vue CHANGED
@@ -101,7 +101,6 @@
101
101
  <template #props-panel>
102
102
  <slot name="props-panel">
103
103
  <PropsPanel
104
- :extend-state="extendFormState"
105
104
  :disabled-show-src="disabledShowSrc"
106
105
  @mounted="propsPanelMountedHandler"
107
106
  @unmounted="propsPanelUnmountedHandler"
@@ -140,7 +139,9 @@ import { computed, provide } from 'vue';
140
139
 
141
140
  import type { MApp } from '@tmagic/core';
142
141
  import { M_THEME_KEY } from '@tmagic/design';
142
+ import { FORM_CONTEXT_KEY } from '@tmagic/form';
143
143
 
144
+ import { useEditorFormContext } from './hooks/use-form-context';
144
145
  import Framework from './layouts/Framework.vue';
145
146
  import TMagicNavMenu from './layouts/NavMenu.vue';
146
147
  import FormPanel from './layouts/props-panel/FormPanel.vue';
@@ -160,7 +161,7 @@ import stageOverlayService from './services/stageOverlay';
160
161
  import storageService from './services/storage';
161
162
  import uiService from './services/ui';
162
163
  import keybindingConfig from './utils/keybinding-config';
163
- import { defaultEditorProps, EditorProps } from './editorProps';
164
+ import { defaultEditorProps, EditorProps, ENABLE_PROPS_FORM_VALIDATE } from './editorProps';
164
165
  import { initServiceEvents, initServiceState } from './initService';
165
166
  import type { TreeNodeData } from './type';
166
167
  import type { EditorSlots, EventBus, Services, StageOptions } from './type';
@@ -218,6 +219,7 @@ const stageOptions: StageOptions = {
218
219
  containerHighlightClassName: props.containerHighlightClassName,
219
220
  containerHighlightDuration: props.containerHighlightDuration,
220
221
  containerHighlightType: props.containerHighlightType,
222
+ containerHighlightAddOnly: props.containerHighlightAddOnly,
221
223
  disabledDragStart: props.disabledDragStart,
222
224
  renderType: props.renderType,
223
225
  guidesOptions: props.guidesOptions,
@@ -233,13 +235,28 @@ provide('services', services);
233
235
 
234
236
  provide('codeOptions', props.codeOptions);
235
237
  provide('stageOptions', stageOptions);
238
+ /** 是否启用「属性配置表单校验」联动能力,供 PropsPanel / FormPanel 判断校验失败时是否仍更新节点并记录错误 */
239
+ provide(ENABLE_PROPS_FORM_VALIDATE, props.enablePropsFormValidate ?? false);
236
240
  /**
237
- * 把顶层 `extendFormState` 提供给非 PropsPanel 链路上的组件使用(例如历史差异对话框 HistoryDiffDialog
238
- * 内部的 CompareForm)。这样所有依赖业务上下文的表单 filterFunction 都能拿到一致的扩展状态,
239
- * 与 PropsPanel 通过 `:extend-state` 显式传入的方式保持等价。
241
+ * 编辑器注入给整棵表单树的业务上下文(`services` / `stage`),属性面板、对比表单、
242
+ * 侧边栏里的嵌套 MForm 都通过 inject 自动继承。
243
+ *
244
+ * 业务方要追加自己的字段,在 `<MEditor>` 外层再 `provide(FORM_CONTEXT_KEY, computed(...))`
245
+ * 即可,配置回调统一通过 `mForm.xxx` 读取。
240
246
  */
241
- provide('extendFormState', props.extendFormState);
247
+ provide(
248
+ FORM_CONTEXT_KEY,
249
+ useEditorFormContext(() => services),
250
+ );
242
251
 
252
+ // 用 computed 包一层再 provide,否则传下去的是 provide 那一刻的值快照,
253
+ // props.isLargeStageContainer 后续变化不会同步到子孙(如 @tmagic/design/ColorPicker)。
254
+ // 子孙侧 `inject<ComputedRef<boolean>>('isLargeStageContainer', computed(() => false))`
255
+ // 用 `.value` 或模板自动解包读取即可拿到最新值。
256
+ provide(
257
+ 'isLargeStageContainer',
258
+ computed(() => props.isLargeStageContainer),
259
+ );
243
260
  /**
244
261
  * 把历史记录面板的自定义扩展 tab 提供给深层的 HistoryListPanel(它挂在 NavMenu 中,
245
262
  * 以 markRaw component 形式渲染,无法直接通过 props 透传)。业务方可借此在历史记录
@@ -4,7 +4,9 @@
4
4
  v-model:visible="boxVisible"
5
5
  v-model:width="width"
6
6
  v-model:height="codeBlockEditorHeight"
7
+ :body-style="{ padding: '0 16px' }"
7
8
  :title="content.name ? `${disabled ? '查看' : '编辑'}${content.name}` : '新增代码'"
9
+ :framework-width="frameworkWidth"
8
10
  :position="boxPosition"
9
11
  :before-close="beforeClose"
10
12
  >
@@ -206,6 +208,7 @@ const closedHandler = () => {
206
208
 
207
209
  const parentFloating = inject<Ref<HTMLDivElement | null>>('parentFloating', ref(null));
208
210
  const { boxPosition, calcBoxPosition } = useNextFloatBoxPosition(uiService, parentFloating);
211
+ const frameworkWidth = computed(() => uiService.get('frameworkRect')?.width || 0);
209
212
 
210
213
  watch(boxVisible, (visible) => {
211
214
  nextTick(() => {
@@ -15,7 +15,13 @@
15
15
  <script lang="ts" setup>
16
16
  import { computed, useTemplateRef } from 'vue';
17
17
 
18
- import { type ContainerChangeEventData, type FormItemConfig, type FormValue, MForm } from '@tmagic/form';
18
+ import {
19
+ type ContainerChangeEventData,
20
+ defineFormItem,
21
+ type FormItemConfig,
22
+ type FormValue,
23
+ MForm,
24
+ } from '@tmagic/form';
19
25
 
20
26
  import type { CodeParamStatement } from '@editor/type';
21
27
  import { error } from '@editor/utils';
@@ -41,13 +47,13 @@ const emit = defineEmits(['change']);
41
47
  const formRef = useTemplateRef<InstanceType<typeof MForm>>('form');
42
48
 
43
49
  const getFormConfig = (items: FormItemConfig[] = []) => [
44
- {
50
+ defineFormItem({
45
51
  type: 'fieldset',
46
52
  items,
47
53
  legend: '参数',
48
- labelWidth: '120px',
54
+ labelPosition: 'top',
49
55
  name: props.name,
50
- },
56
+ }),
51
57
  ];
52
58
 
53
59
  const codeParamsConfig = computed(() =>
@@ -10,104 +10,45 @@
10
10
  :is-compare="true"
11
11
  :disabled="true"
12
12
  :label-width="labelWidth"
13
- :extend-state="extendState"
13
+ :context="formContext"
14
14
  :show-diff="showDiff"
15
+ :self-diff-field-types="selfDiffFieldTypes"
16
+ :size="size"
15
17
  ></MForm>
16
18
  </div>
17
19
  </template>
18
20
 
19
21
  <script lang="ts" setup>
20
- import { computed, inject, provide, type Ref, ref, type ShallowRef, useTemplateRef, watch, watchEffect } from 'vue';
22
+ import { computed, type Ref, type ShallowRef } from 'vue';
21
23
  import { isEqual } from 'lodash-es';
22
24
 
23
- import { type CodeBlockContent, type DataSourceSchema, HookType, type MNode } from '@tmagic/core';
24
- import { type FormConfig, type FormState, type FormValue, MForm } from '@tmagic/form';
25
+ import { type CodeBlockContent, HookType } from '@tmagic/core';
26
+ import { type FormConfig, type FormValue, MForm } from '@tmagic/form';
25
27
 
26
- import { useServices } from '@editor/hooks/use-services';
27
- import type { CompareCategory, CompareFormLoadConfig, Services } from '@editor/type';
28
- import { getCodeBlockFormConfig } from '@editor/utils/code-block';
28
+ import { useCompareForm } from '@editor/hooks/use-compare-form';
29
+ import type { CompareFormBaseProps } from '@editor/type';
29
30
 
30
31
  defineOptions({
31
32
  name: 'MEditorCompareForm',
32
33
  });
33
34
 
34
35
  const props = withDefaults(
35
- defineProps<{
36
- /** 当前值(修改后的值) */
37
- value: Partial<MNode> | Partial<DataSourceSchema> | Partial<CodeBlockContent> | Record<string, any>;
38
- /** 用于对比的旧值(修改前的值) */
39
- lastValue?: Partial<MNode> | Partial<DataSourceSchema> | Partial<CodeBlockContent> | Record<string, any>;
40
- /**
41
- * 类型说明:
42
- * - `category` 为 `node` 时,`type` 为节点组件的类型,例如 'text'、'button'、'page'、'container' 等
43
- * - `category` 为 `data-source` 时,`type` 为数据源类型,例如 'base'、'http'
44
- * - `category` 为 `code-block` 时,`type` 可不传
45
- */
46
- type?: string;
47
- /** 表单配置类别,决定从哪里取 FormConfig */
48
- category?: CompareCategory;
49
- /** 数据源代码块场景下的数据源类型(base/http),用于代码块表单中"执行时机"展示 */
50
- dataSourceType?: string;
51
- labelWidth?: string;
52
- /**
53
- * 外层容器高度。设置后表单内容超出时会在 CompareForm 内部出现滚动条,
54
- * 避免 dialog / 面板使用方需要自行处理滚动。可传任意 CSS 长度,例如 `60vh` / `400px` / `100%`。
55
- */
56
- height?: string;
57
- /**
58
- * 用户自定义注入到 MForm.formState 的扩展字段,与 Editor 顶层的 `extendFormState`、
59
- * PropsPanel 的 `extend-state` 语义一致。表单 item 的 `display` / `disabled` 等
60
- * filterFunction 经常依赖这里注入的字段(如 stage、自定义业务上下文等),
61
- * 因此在差异对比场景下也需要透传,避免出现 `formState.xxx is undefined` 的运行时错误。
62
- */
63
- extendState?: (_state: FormState) => Record<string, any> | Promise<Record<string, any>>;
64
- /**
65
- * 自定义 FormConfig 加载逻辑。传入后将接管内置的按 `category`(node/data-source/code-block)
66
- * 取配置逻辑,调用方可根据业务自行返回(或异步返回)表单配置。可通过
67
- * `ctx.defaultLoadConfig()` 复用默认结果再做二次加工。返回的 config 直接用于对比展示。
68
- */
69
- loadConfig?: CompareFormLoadConfig;
70
- /** 编辑器服务集合,由调用方传入(不再通过 inject('services') 获取)。 */
71
- services: Services;
72
- }>(),
36
+ defineProps<
37
+ CompareFormBaseProps & {
38
+ /** 用于对比的旧值(修改前的值) */
39
+ lastValue?: CompareFormBaseProps['value'];
40
+ /** 需要走 self diff 的字段类型(例如 mod-cond)。 */
41
+ selfDiffFieldTypes?: string[];
42
+ }
43
+ >(),
73
44
  {
74
45
  category: 'node',
75
46
  labelWidth: '120px',
76
- services: () => useServices(),
77
47
  },
78
48
  );
79
49
 
80
- const { propsService, dataSourceService, codeBlockService, editorService } = props.services;
81
-
82
- provide('services', props.services);
83
-
84
- const config = ref<FormConfig>([]);
85
-
86
- /** vs-code 编辑器的 monaco 配置项,沿用 Editor 顶层 provide('codeOptions', ...) 的注入。 */
87
- const codeOptions = inject<Record<string, any>>('codeOptions', {});
88
-
89
- /** 将代码块的 content 字段统一成字符串,便于在表单/对比中展示 */
90
- const normalizeCodeBlockValue = (
91
- v: Partial<CodeBlockContent> | Record<string, any> | undefined,
92
- ): Record<string, any> => {
93
- if (!v) return {};
94
- const next: Record<string, any> = { ...v };
95
- if (next.content && typeof next.content !== 'string') {
96
- try {
97
- next.content = next.content.toString();
98
- } catch {
99
- next.content = '';
100
- }
101
- }
102
- return next;
103
- };
104
-
105
- const currentValues = computed<FormValue>(() => {
106
- if (props.category === 'code-block') {
107
- return normalizeCodeBlockValue(props.value as Partial<CodeBlockContent>);
108
- }
109
- return (props.value || {}) as FormValue;
110
- });
50
+ const { config, currentValues, wrapperStyle, formContext, loadConfig, formRef, normalizeCodeBlockValue } =
51
+ useCompareForm(props);
111
52
 
112
53
  const lastValuesProcessed = computed<FormValue>(() => {
113
54
  if (props.category === 'code-block') {
@@ -116,24 +57,11 @@ const lastValuesProcessed = computed<FormValue>(() => {
116
57
  return (props.lastValue || {}) as FormValue;
117
58
  });
118
59
 
119
- /**
120
- * 外层包裹层的样式:当传入 `height` 时启用固定高度 + 内部滚动,
121
- * 这样滚动条会出现在 CompareForm 内部,避免父容器(如 Dialog)自身也产生滚动。
122
- */
123
- const wrapperStyle = computed(() => {
124
- if (!props.height) return undefined;
125
- return {
126
- height: props.height,
127
- overflow: 'auto',
128
- } as Record<string, string>;
129
- });
130
-
131
60
  /**
132
61
  * `code-select` 字段在历史数据中存在两种"语义为空"的形态:
133
62
  * - 字符串 `''`(旧数据 / 用户从未配置过钩子);
134
- * - `{ hookType: HookType.CODE, hookData: [] }`(CodeSelect.vue 在挂载时
135
- * 写入的默认结构,参见 packages/editor/src/fields/CodeSelect.vue 中
136
- * `props.model[props.name] = { hookType: HookType.CODE, hookData: [] }`)。
63
+ * - `{ hookType: HookType.CODE, hookData: [] }`(`normalizeCodeSelectValue`
64
+ * 写入的默认结构)。
137
65
  *
138
66
  * 直接 `isEqual` 会把两者判为不等,从而在历史对比里对每个未配置过钩子的组件
139
67
  * 都展示一份"差异",体验很糟糕。这里把它们视为相等,跳过对比。
@@ -156,104 +84,6 @@ const showDiff = ({ curValue, lastValue, config }: { curValue: any; lastValue: a
156
84
  return !isEqual(curValue, lastValue);
157
85
  };
158
86
 
159
- const removeStyleDisplayConfig = (formConfig: FormConfig): FormConfig =>
160
- formConfig.map((item) => {
161
- if (!('type' in item)) return item;
162
- if (item?.type !== 'tab' || !Array.isArray(item.items)) return item;
163
-
164
- return {
165
- ...item,
166
- items: item.items.map((tabPane) => {
167
- if (tabPane?.title !== '样式' || !Array.isArray(tabPane.items)) return tabPane;
168
-
169
- return {
170
- ...tabPane,
171
- display: true,
172
- };
173
- }),
174
- };
175
- });
176
-
177
- /**
178
- * 内置的默认 FormConfig 加载逻辑:按 `category` 从对应 service / 工具取配置。
179
- * 作为 ctx.defaultLoadConfig 透传给自定义 `loadConfig`,方便复用与二次加工。
180
- */
181
- const defaultLoadConfig = async (): Promise<FormConfig> => {
182
- switch (props.category) {
183
- case 'node': {
184
- if (!props.type) {
185
- return [];
186
- }
187
- return removeStyleDisplayConfig(
188
- await propsService.getPropsConfig(props.type, { node: props.value as unknown as MNode }),
189
- );
190
- }
191
- case 'data-source': {
192
- const config = dataSourceService.getFormConfig(props.type || 'base');
193
- // 数据源表单外层 tab 的「数据定义」项 status 为 'fields',tab-pane name 随之为 'fields'。
194
- // 未显式设置 active 时,Tabs 默认取 '0',与 'fields' 不匹配会导致打开弹窗时无默认激活项,
195
- // 这里与 DataSourceConfigPanel 保持一致,默认激活「数据定义」tab。
196
- return config.map((item) => ('type' in item && item.type === 'tab' ? { ...item, active: 'fields' } : item));
197
- }
198
- case 'code-block': {
199
- return getCodeBlockFormConfig({
200
- paramColConfig: codeBlockService.getParamsColConfig(),
201
- // 通过传入 dataSourceType 间接表达"是数据源代码块"——在对比场景下 props.dataSourceType
202
- // 由调用方按 step 上下文显式传入,未传则视为普通代码块,「执行时机」字段隐藏。
203
- isDataSource: () => Boolean(props.dataSourceType),
204
- dataSourceType: () => props.dataSourceType,
205
- codeOptions,
206
- // 对比模式只读,不需要校验/语法检查
207
- editable: false,
208
- });
209
- }
210
- default:
211
- return [];
212
- }
213
- };
214
-
215
- const loadConfig = async () => {
216
- if (props.loadConfig) {
217
- config.value = await props.loadConfig({
218
- category: props.category,
219
- type: props.type,
220
- dataSourceType: props.dataSourceType,
221
- defaultLoadConfig,
222
- });
223
- return;
224
- }
225
-
226
- config.value = await defaultLoadConfig();
227
- };
228
-
229
- watch(
230
- [() => props.category, () => props.type, () => props.dataSourceType, () => props.loadConfig],
231
- () => {
232
- loadConfig();
233
- },
234
- { immediate: true },
235
- );
236
-
237
- const formRef = useTemplateRef<InstanceType<typeof MForm>>('form');
238
-
239
- /**
240
- * 把 services / stage 注入 MForm 的 formState,避免 propsService 注入的表单配置中
241
- * 形如 `display: ({ services }) => services.uiService.get(...)` 的 filterFunction
242
- * 在执行时拿不到 `formState.services` 而报错。
243
- *
244
- * 与 props-panel/FormPanel.vue 中的注入方式保持一致:
245
- * - services:整个 useServices() 返回的服务集合;
246
- * - stage:当前 editorService.get('stage') 的最新值。
247
- */
248
- const stage = computed(() => editorService.get('stage'));
249
-
250
- watchEffect(() => {
251
- if (formRef.value) {
252
- formRef.value.formState.stage = stage.value;
253
- formRef.value.formState.services = props.services;
254
- }
255
- });
256
-
257
87
  defineExpose<{
258
88
  form: ShallowRef<InstanceType<typeof MForm> | null>;
259
89
  config: Ref<FormConfig>;
@@ -128,20 +128,42 @@ const outsideClickHideHandler = (e: MouseEvent) => {
128
128
  hide();
129
129
  };
130
130
 
131
- const setPosition = (e: { clientY: number; clientX: number }) => {
132
- const menuHeight = menuEl.value?.clientHeight || 0;
131
+ // 根据菜单实际尺寸修正位置,避免超出可视范围
132
+ const fixPosition = () => {
133
+ const menu = menuEl.value;
134
+ if (!menu || !visible.value) return;
135
+
136
+ const menuHeight = menu.clientHeight;
137
+ const menuWidth = menu.clientWidth;
138
+
139
+ let { top, left } = menuPosition.value;
140
+
141
+ if (top + menuHeight > document.body.clientHeight) {
142
+ top = Math.max(0, document.body.clientHeight - menuHeight);
143
+ }
144
+
145
+ if (left + menuWidth > document.body.clientWidth) {
146
+ left = Math.max(0, document.body.clientWidth - menuWidth);
147
+ }
133
148
 
134
- let top = e.clientY;
135
- if (menuHeight + e.clientY > document.body.clientHeight) {
136
- top = document.body.clientHeight - menuHeight;
149
+ if (top !== menuPosition.value.top || left !== menuPosition.value.left) {
150
+ menuPosition.value = { top, left };
137
151
  }
152
+ };
138
153
 
154
+ const setPosition = (e: { clientY: number; clientX: number }) => {
139
155
  menuPosition.value = {
140
- top,
156
+ top: e.clientY,
141
157
  left: e.clientX,
142
158
  };
159
+ fixPosition();
143
160
  };
144
161
 
162
+ // 菜单大小动态变化(如菜单项更新)后重新修正位置
163
+ const resizeObserver = new ResizeObserver(() => {
164
+ fixPosition();
165
+ });
166
+
145
167
  const show = (e?: { clientY: number; clientX: number }) => {
146
168
  visible.value = true;
147
169
 
@@ -186,12 +208,18 @@ const mouseenterHandler = () => {
186
208
  };
187
209
 
188
210
  onMounted(() => {
211
+ if (menuEl.value) {
212
+ resizeObserver.observe(menuEl.value);
213
+ }
214
+
189
215
  if (props.isSubMenu) return;
190
216
 
191
217
  globalThis.addEventListener('mousedown', outsideClickHideHandler, true);
192
218
  });
193
219
 
194
220
  onBeforeUnmount(() => {
221
+ resizeObserver.disconnect();
222
+
195
223
  if (props.isSubMenu) return;
196
224
 
197
225
  globalThis.removeEventListener('mousedown', outsideClickHideHandler, true);
@@ -3,6 +3,7 @@
3
3
  <div
4
4
  ref="target"
5
5
  :class="['m-editor-float-box', themeClass]"
6
+ v-bind="$attrs"
6
7
  :style="{ ...style, zIndex: curZIndex }"
7
8
  @mousedown="nextZIndex"
8
9
  >
@@ -14,7 +15,7 @@
14
15
  <TMagicButton link size="small" @click="closeHandler"><MIcon :icon="Close"></MIcon></TMagicButton>
15
16
  </div>
16
17
  </div>
17
- <div class="m-editor-float-box-body" :style="{ height: `${bodyHeight}px` }">
18
+ <div class="m-editor-float-box-body" :style="{ height: `${bodyHeight}px`, ...bodyStyle }">
18
19
  <slot name="body"></slot>
19
20
  </div>
20
21
  </div>
@@ -22,14 +23,13 @@
22
23
  </template>
23
24
 
24
25
  <script setup lang="ts">
25
- import { computed, nextTick, onBeforeUnmount, provide, ref, useTemplateRef, watch } from 'vue';
26
+ import { computed, type CSSProperties, nextTick, onBeforeUnmount, provide, ref, useTemplateRef, watch } from 'vue';
26
27
  import { Close } from '@element-plus/icons-vue';
27
28
  import VanillaMoveable from 'moveable';
28
29
 
29
30
  import { TMagicButton, useThemeClass, useZIndex } from '@tmagic/design';
30
31
 
31
32
  import MIcon from '@editor/components/Icon.vue';
32
- import { useServices } from '@editor/hooks/use-services';
33
33
 
34
34
  interface Position {
35
35
  left: number;
@@ -44,11 +44,18 @@ const props = withDefaults(
44
44
  defineProps<{
45
45
  position?: Position;
46
46
  title?: string;
47
+ bodyStyle?: CSSProperties;
48
+ /** 浮窗初始样式,会与内部计算样式合并,外部传入优先 */
49
+ initialStyle?: CSSProperties;
50
+ /** 用于约束浮窗 left 的容器宽度,传入时按宽度收敛 left,避免超出右边界;默认取视窗宽度 */
51
+ frameworkWidth?: number;
47
52
  beforeClose?: (_done: (_cancel?: boolean) => void) => void;
48
53
  }>(),
49
54
  {
50
55
  title: '',
51
56
  position: () => ({ left: 0, top: 0 }),
57
+ initialStyle: () => ({}),
58
+ frameworkWidth: 0,
52
59
  },
53
60
  );
54
61
 
@@ -77,12 +84,11 @@ const bodyHeight = computed(() => {
77
84
  return 'auto';
78
85
  });
79
86
 
80
- const { uiService } = useServices();
81
- const frameworkWidth = computed(() => uiService.get('frameworkRect').width || 0);
82
87
  const style = computed(() => {
83
88
  let { left } = props.position;
84
- if (width.value) {
85
- left = left + width.value > frameworkWidth.value ? frameworkWidth.value - width.value : left;
89
+ const frameworkWidth = props.frameworkWidth || globalThis.window?.innerWidth || 0;
90
+ if (width.value && frameworkWidth) {
91
+ left = left + width.value > frameworkWidth ? frameworkWidth - width.value : left;
86
92
  }
87
93
 
88
94
  return {
@@ -90,11 +96,60 @@ const style = computed(() => {
90
96
  top: `${props.position.top}px`,
91
97
  width: width.value ? `${width.value}px` : 'auto',
92
98
  height: height.value ? `${height.value}px` : 'auto',
99
+ ...props.initialStyle,
93
100
  };
94
101
  });
95
102
 
96
103
  let moveable: VanillaMoveable | null = null;
97
104
 
105
+ // 拖拽/缩放时用于覆盖 iframe 的遮罩,防止鼠标进入 iframe 区域后事件被 iframe 吞掉导致拖拽丢失
106
+ let dragMask: HTMLDivElement | null = null;
107
+ let dragMaskVisible = false;
108
+
109
+ // 兜底:正常情况下遮罩由 moveable 的 dragEnd/resizeEnd 移除;但某些极端场景
110
+ // (拖拽中鼠标移出窗口后松开、alt-tab 切走窗口失焦、标签页被隐藏等)结束事件不会触发,
111
+ // 会导致全屏透明遮罩残留、整个编辑器无法点击。这里挂全局 pointerup/blur/visibilitychange 强制收尾。
112
+ const bindDragMaskSafety = () => {
113
+ globalThis.window?.addEventListener('pointerup', hideDragMask, true);
114
+ globalThis.window?.addEventListener('blur', hideDragMask);
115
+ globalThis.document?.addEventListener('visibilitychange', hideDragMask);
116
+ };
117
+
118
+ const unbindDragMaskSafety = () => {
119
+ globalThis.window?.removeEventListener('pointerup', hideDragMask, true);
120
+ globalThis.window?.removeEventListener('blur', hideDragMask);
121
+ globalThis.document?.removeEventListener('visibilitychange', hideDragMask);
122
+ };
123
+
124
+ const showDragMask = () => {
125
+ if (dragMaskVisible) {
126
+ return;
127
+ }
128
+ if (!dragMask) {
129
+ dragMask = globalThis.document.createElement('div');
130
+ dragMask.className = 'm-editor-float-box-drag-mask';
131
+ }
132
+ globalThis.document.body.appendChild(dragMask);
133
+ dragMaskVisible = true;
134
+ bindDragMaskSafety();
135
+
136
+ // 拖拽标题时,root 上的 @mousedown="nextZIndex" 会把浮窗 z-index 抬高,
137
+ // 若此时才读取会拿到旧值导致遮罩被浮窗(及其内部 iframe)盖住,故用 nextTick 在 z-index 稳定后再设置到浮窗之上
138
+ const setMaskZIndex = () => {
139
+ if (dragMask) {
140
+ dragMask.style.zIndex = `${curZIndex.value + 1}`;
141
+ }
142
+ };
143
+ setMaskZIndex();
144
+ nextTick(setMaskZIndex);
145
+ };
146
+
147
+ const hideDragMask = () => {
148
+ unbindDragMaskSafety();
149
+ dragMask?.parentNode?.removeChild(dragMask);
150
+ dragMaskVisible = false;
151
+ };
152
+
98
153
  const initMoveable = () => {
99
154
  moveable = new VanillaMoveable(globalThis.document.body, {
100
155
  className: 'm-editor-floating-box-moveable',
@@ -112,6 +167,14 @@ const initMoveable = () => {
112
167
  bounds: { left: 0, top: 0, right: 0, bottom: 0, position: 'css' },
113
168
  });
114
169
 
170
+ // 仅在真正发生拖拽/缩放位移时插入遮罩:moveable 的 dragStart/resizeStart 在 mousedown 时即触发,
171
+ // 若此时就盖遮罩,会盖住浮窗本身导致 mouseup 落在遮罩上、关闭按钮的 click 无法触发(点击关闭不了)。
172
+ // 改为在 drag/resize(实际位移)时才显示,纯点击不再触发遮罩。
173
+ moveable.on('drag', showDragMask);
174
+ moveable.on('resize', showDragMask);
175
+ moveable.on('dragEnd', hideDragMask);
176
+ moveable.on('resizeEnd', hideDragMask);
177
+
115
178
  moveable.on('drag', (e) => {
116
179
  e.target.style.transform = e.transform;
117
180
  });
@@ -126,6 +189,7 @@ const initMoveable = () => {
126
189
  };
127
190
 
128
191
  const destroyMoveable = () => {
192
+ hideDragMask();
129
193
  moveable?.destroy();
130
194
  moveable = null;
131
195
  };