@tmagic/editor 1.8.0-beta.2 → 1.8.0-beta.20

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 (306) hide show
  1. package/dist/es/Editor.vue_vue_type_script_setup_true_lang.js +43 -9
  2. package/dist/es/components/CodeBlockEditor.vue_vue_type_script_setup_true_lang.js +8 -4
  3. package/dist/es/components/CodeParams.vue_vue_type_script_setup_true_lang.js +3 -2
  4. package/dist/es/components/CompareForm.vue_vue_type_script_setup_true_lang.js +22 -98
  5. package/dist/es/components/ContentMenu.vue_vue_type_script_setup_true_lang.js +32 -9
  6. package/dist/es/components/FloatingBox.vue_vue_type_script_setup_true_lang.js +68 -17
  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 +1 -1
  9. package/dist/es/components/ScrollBar.js +0 -1
  10. package/dist/es/components/ScrollBar.vue_vue_type_script_setup_true_lang.js +1 -1
  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 +7 -7
  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 +58 -0
  19. package/dist/es/editorProps.js +9 -1
  20. package/dist/es/fields/Code.vue_vue_type_script_setup_true_lang.js +16 -5
  21. package/dist/es/fields/CodeLink.vue_vue_type_script_setup_true_lang.js +7 -7
  22. package/dist/es/fields/CodeSelect.vue_vue_type_script_setup_true_lang.js +81 -44
  23. package/dist/es/fields/CodeSelectCol.vue_vue_type_script_setup_true_lang.js +10 -3
  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 +13 -6
  26. package/dist/es/fields/DataSourceFieldSelect/Index.vue_vue_type_script_setup_true_lang.js +11 -8
  27. package/dist/es/fields/DataSourceFields.vue_vue_type_script_setup_true_lang.js +39 -12
  28. package/dist/es/fields/DataSourceInput.vue_vue_type_script_setup_true_lang.js +11 -20
  29. package/dist/es/fields/DataSourceMethodSelect.vue_vue_type_script_setup_true_name_true_lang.js +11 -6
  30. package/dist/es/fields/DataSourceMethods.vue_vue_type_script_setup_true_lang.js +30 -14
  31. package/dist/es/fields/DataSourceMocks.vue_vue_type_script_setup_true_lang.js +11 -4
  32. package/dist/es/fields/DataSourceSelect.vue_vue_type_script_setup_true_lang.js +5 -2
  33. package/dist/es/fields/DisplayConds.vue_vue_type_script_setup_true_lang.js +38 -6
  34. package/dist/es/fields/EventSelect.vue_vue_type_script_setup_true_lang.js +151 -153
  35. package/dist/es/fields/KeyValue.vue_vue_type_script_setup_true_lang.js +5 -2
  36. package/dist/es/fields/PageFragmentSelect.vue_vue_type_script_setup_true_lang.js +5 -2
  37. package/dist/es/fields/StyleSetter/Index.vue_vue_type_script_setup_true_lang.js +8 -10
  38. package/dist/es/fields/StyleSetter/components/BackgroundPosition.vue_vue_type_script_setup_true_lang.js +5 -2
  39. package/dist/es/fields/StyleSetter/components/Border.vue_vue_type_script_setup_true_lang.js +28 -6
  40. package/dist/es/fields/StyleSetter/components/Box.vue_vue_type_script_setup_true_lang.js +1 -1
  41. package/dist/es/fields/StyleSetter/icons/align-items/Center.js +31 -0
  42. package/dist/es/fields/StyleSetter/icons/align-items/FlexEnd.js +31 -0
  43. package/dist/es/fields/StyleSetter/icons/align-items/FlexStart.js +31 -0
  44. package/dist/es/fields/StyleSetter/icons/align-items/SpaceAround.js +50 -0
  45. package/dist/es/fields/StyleSetter/icons/align-items/SpaceBetween.js +50 -0
  46. package/dist/es/fields/StyleSetter/icons/background-repeat/NoRepeat.js +7 -7
  47. package/dist/es/fields/StyleSetter/icons/background-repeat/Repeat.js +6 -3
  48. package/dist/es/fields/StyleSetter/icons/background-repeat/RepeatX.js +29 -6
  49. package/dist/es/fields/StyleSetter/icons/background-repeat/RepeatY.js +32 -6
  50. package/dist/es/fields/StyleSetter/icons/display/Block.js +1 -1
  51. package/dist/es/fields/StyleSetter/icons/display/Flex.js +1 -1
  52. package/dist/es/fields/StyleSetter/icons/display/Inline.js +1 -1
  53. package/dist/es/fields/StyleSetter/icons/display/InlineBlock.js +1 -1
  54. package/dist/es/fields/StyleSetter/icons/display/None.js +1 -1
  55. package/dist/es/fields/StyleSetter/icons/flex-direction/Column.js +11 -3
  56. package/dist/es/fields/StyleSetter/icons/flex-direction/ColumnReverse.js +11 -3
  57. package/dist/es/fields/StyleSetter/icons/flex-direction/Row.js +11 -3
  58. package/dist/es/fields/StyleSetter/icons/flex-direction/RowReverse.js +11 -3
  59. package/dist/es/fields/StyleSetter/icons/justify-content/Center.js +17 -3
  60. package/dist/es/fields/StyleSetter/icons/justify-content/FlexEnd.js +19 -3
  61. package/dist/es/fields/StyleSetter/icons/justify-content/FlexStart.js +19 -3
  62. package/dist/es/fields/StyleSetter/icons/justify-content/SpaceAround.js +37 -3
  63. package/dist/es/fields/StyleSetter/icons/justify-content/SpaceBetween.js +33 -3
  64. package/dist/es/fields/StyleSetter/icons/text-align/Center.js +1 -1
  65. package/dist/es/fields/StyleSetter/icons/text-align/Left.js +1 -1
  66. package/dist/es/fields/StyleSetter/icons/text-align/Right.js +1 -1
  67. package/dist/es/fields/StyleSetter/pro/Background.vue_vue_type_script_setup_true_lang.js +56 -30
  68. package/dist/es/fields/StyleSetter/pro/Border.vue_vue_type_script_setup_true_lang.js +7 -4
  69. package/dist/es/fields/StyleSetter/pro/Font.vue_vue_type_script_setup_true_lang.js +35 -26
  70. package/dist/es/fields/StyleSetter/pro/Layout.vue_vue_type_script_setup_true_lang.js +76 -48
  71. package/dist/es/fields/StyleSetter/pro/Position.vue_vue_type_script_setup_true_lang.js +29 -23
  72. package/dist/es/fields/StyleSetter/pro/Transform.vue_vue_type_script_setup_true_lang.js +7 -4
  73. package/dist/es/fields/UISelect.js +0 -1
  74. package/dist/es/fields/UISelect.vue_vue_type_script_setup_true_lang.js +5 -2
  75. package/dist/es/hooks/use-code-block-edit.js +6 -3
  76. package/dist/es/hooks/use-compare-form.js +119 -0
  77. package/dist/es/hooks/use-data-source-edit.js +5 -2
  78. package/dist/es/hooks/use-stage.js +9 -4
  79. package/dist/es/icons/CenterIcon.vue_vue_type_script_setup_true_lang.js +1 -1
  80. package/dist/es/icons/CodeIcon.vue_vue_type_script_setup_true_lang.js +1 -1
  81. package/dist/es/icons/DatasourceIcon.js +17 -0
  82. package/dist/es/icons/FolderMinusIcon.vue_vue_type_script_setup_true_lang.js +1 -1
  83. package/dist/es/index.js +24 -10
  84. package/dist/es/initService.js +19 -13
  85. package/dist/es/layouts/AddPageBox.vue_vue_type_script_setup_true_lang.js +1 -1
  86. package/dist/es/layouts/CodeEditor.vue_vue_type_script_setup_true_lang.js +24 -12
  87. package/dist/es/layouts/Framework.vue_vue_type_script_setup_true_lang.js +25 -18
  88. package/dist/es/layouts/NavMenu.vue_vue_type_script_setup_true_lang.js +4 -4
  89. package/dist/es/layouts/NavMenuColumn.vue_vue_type_script_setup_true_lang.js +1 -1
  90. package/dist/es/layouts/history-list/Bucket.vue_vue_type_script_setup_true_lang.js +25 -38
  91. package/dist/es/layouts/history-list/BucketTab.js +5 -0
  92. package/dist/es/layouts/history-list/BucketTab.vue_vue_type_script_setup_true_lang.js +62 -0
  93. package/dist/es/layouts/history-list/GroupRow.vue_vue_type_script_setup_true_lang.js +177 -88
  94. package/dist/es/layouts/history-list/HistoryDiffDialog.vue_vue_type_script_setup_true_lang.js +139 -37
  95. package/dist/es/layouts/history-list/HistoryListPanel.vue_vue_type_script_setup_true_lang.js +164 -107
  96. package/dist/es/layouts/history-list/InitialRow.vue_vue_type_script_setup_true_lang.js +44 -9
  97. package/dist/es/layouts/history-list/PageTab.vue_vue_type_script_setup_true_lang.js +49 -53
  98. package/dist/es/layouts/history-list/composables.js +138 -108
  99. package/dist/es/layouts/history-list/useHistoryList.js +56 -0
  100. package/dist/es/layouts/history-list/useHistoryRevert.js +317 -0
  101. package/dist/es/layouts/page-bar/AddButton.vue_vue_type_script_setup_true_lang.js +1 -1
  102. package/dist/es/layouts/page-bar/PageBar.vue_vue_type_script_setup_true_lang.js +5 -3
  103. package/dist/es/layouts/page-bar/PageBarScrollContainer.vue_vue_type_script_setup_true_lang.js +1 -1
  104. package/dist/es/layouts/page-bar/PageList.vue_vue_type_script_setup_true_lang.js +1 -1
  105. package/dist/es/layouts/page-bar/Search.vue_vue_type_script_setup_true_lang.js +2 -2
  106. package/dist/es/layouts/props-panel/FormPanel.vue_vue_type_script_setup_true_lang.js +50 -7
  107. package/dist/es/layouts/props-panel/PropsPanel.vue_vue_type_script_setup_true_lang.js +33 -13
  108. package/dist/es/layouts/props-panel/use-style-panel.js +3 -2
  109. package/dist/es/layouts/sidebar/ComponentListPanel.vue_vue_type_script_setup_true_lang.js +3 -3
  110. package/dist/es/layouts/sidebar/Sidebar.vue_vue_type_script_setup_true_lang.js +26 -38
  111. package/dist/es/layouts/sidebar/code-block/CodeBlockList.vue_vue_type_script_setup_true_lang.js +4 -4
  112. package/dist/es/layouts/sidebar/code-block/CodeBlockListPanel.vue_vue_type_script_setup_true_lang.js +4 -4
  113. package/dist/es/layouts/sidebar/code-block/useContentMenu.js +19 -4
  114. package/dist/es/layouts/sidebar/data-source/DataSourceAddButton.vue_vue_type_script_setup_true_lang.js +1 -1
  115. package/dist/es/layouts/sidebar/data-source/DataSourceConfigPanel.vue_vue_type_script_setup_true_lang.js +23 -6
  116. package/dist/es/layouts/sidebar/data-source/DataSourceList.vue_vue_type_script_setup_true_lang.js +1 -1
  117. package/dist/es/layouts/sidebar/data-source/DataSourceListPanel.vue_vue_type_script_setup_true_lang.js +27 -5
  118. package/dist/es/layouts/sidebar/data-source/useContentMenu.js +19 -4
  119. package/dist/es/layouts/sidebar/layer/LayerMenu.vue_vue_type_script_setup_true_lang.js +8 -8
  120. package/dist/es/layouts/sidebar/layer/LayerNodeContent.js +5 -0
  121. package/dist/es/layouts/sidebar/layer/LayerNodeContent.vue_vue_type_script_setup_true_lang.js +46 -0
  122. package/dist/es/layouts/sidebar/layer/LayerNodeTool.vue_vue_type_script_setup_true_lang.js +2 -2
  123. package/dist/es/layouts/sidebar/layer/LayerPanel.vue_vue_type_script_setup_true_lang.js +3 -2
  124. package/dist/es/layouts/sidebar/layer/use-click.js +3 -3
  125. package/dist/es/layouts/sidebar/layer/use-node-status.js +2 -2
  126. package/dist/es/layouts/workspace/Breadcrumb.vue_vue_type_script_setup_true_lang.js +1 -1
  127. package/dist/es/layouts/workspace/Workspace.vue_vue_type_script_setup_true_lang.js +1 -1
  128. package/dist/es/layouts/workspace/viewer/NodeListMenu.vue_vue_type_script_setup_true_lang.js +9 -3
  129. package/dist/es/layouts/workspace/viewer/Stage.vue_vue_type_script_setup_true_lang.js +2 -2
  130. package/dist/es/layouts/workspace/viewer/StageOverlay.vue_vue_type_script_setup_true_lang.js +1 -1
  131. package/dist/es/layouts/workspace/viewer/ViewerMenu.vue_vue_type_script_setup_true_lang.js +16 -16
  132. package/dist/es/plugin.js +5 -2
  133. package/dist/es/services/codeBlock.js +137 -56
  134. package/dist/es/services/dataSource.js +122 -52
  135. package/dist/es/services/dep.js +162 -41
  136. package/dist/es/services/editor.js +613 -179
  137. package/dist/es/services/history.js +350 -386
  138. package/dist/es/services/keybinding.js +6 -6
  139. package/dist/es/services/props.js +3 -2
  140. package/dist/es/services/storage.js +2 -2
  141. package/dist/es/services/ui.js +10 -2
  142. package/dist/es/style.css +549 -113
  143. package/dist/es/utils/config.js +4 -1
  144. package/dist/es/utils/const.js +2 -2
  145. package/dist/es/utils/content-menu.js +19 -11
  146. package/dist/es/utils/data-source/index.js +34 -11
  147. package/dist/es/utils/dep/collect-worker-client.js +114 -0
  148. package/dist/es/utils/dep/idle-task.js +47 -22
  149. package/dist/es/utils/dep/worker.js +1 -1
  150. package/dist/es/utils/editor.js +103 -49
  151. package/dist/es/utils/event.js +123 -0
  152. package/dist/es/utils/history.js +220 -0
  153. package/dist/es/utils/indexed-db.js +86 -0
  154. package/dist/es/utils/monaco-editor.js +22 -6
  155. package/dist/es/utils/operator.js +2 -2
  156. package/dist/es/utils/props.js +114 -33
  157. package/dist/es/utils/type-match-rules.js +367 -0
  158. package/dist/es/utils/undo-redo.js +60 -1
  159. package/dist/style.css +549 -113
  160. package/dist/themes/magic-admin.css +3028 -0
  161. package/dist/tmagic-editor.umd.cjs +14273 -10029
  162. package/package.json +8 -8
  163. package/src/Editor.vue +43 -2
  164. package/src/components/CodeBlockEditor.vue +3 -0
  165. package/src/components/CompareForm.vue +18 -146
  166. package/src/components/ContentMenu.vue +44 -8
  167. package/src/components/FloatingBox.vue +84 -9
  168. package/src/components/ScrollBar.vue +0 -67
  169. package/src/components/ToolButton.vue +2 -2
  170. package/src/components/ViewForm.vue +55 -0
  171. package/src/editorProps.ts +30 -0
  172. package/src/fields/Code.vue +10 -2
  173. package/src/fields/CodeLink.vue +2 -5
  174. package/src/fields/CodeSelect.vue +54 -40
  175. package/src/fields/CodeSelectCol.vue +8 -1
  176. package/src/fields/CondOpSelect.vue +2 -24
  177. package/src/fields/DataSourceFieldSelect/FieldSelect.vue +16 -2
  178. package/src/fields/DataSourceFieldSelect/Index.vue +14 -5
  179. package/src/fields/DataSourceFields.vue +42 -8
  180. package/src/fields/DataSourceInput.vue +10 -28
  181. package/src/fields/DataSourceMethodSelect.vue +9 -4
  182. package/src/fields/DataSourceMethods.vue +42 -21
  183. package/src/fields/DataSourceMocks.vue +3 -0
  184. package/src/fields/DisplayConds.vue +18 -1
  185. package/src/fields/EventSelect.vue +145 -161
  186. package/src/fields/StyleSetter/Index.vue +3 -12
  187. package/src/fields/StyleSetter/components/Border.vue +15 -6
  188. package/src/fields/StyleSetter/icons/align-items/Center.vue +19 -0
  189. package/src/fields/StyleSetter/icons/align-items/FlexEnd.vue +19 -0
  190. package/src/fields/StyleSetter/icons/align-items/FlexStart.vue +19 -0
  191. package/src/fields/StyleSetter/icons/align-items/SpaceAround.vue +34 -0
  192. package/src/fields/StyleSetter/icons/align-items/SpaceBetween.vue +34 -0
  193. package/src/fields/StyleSetter/icons/align-items/index.ts +5 -0
  194. package/src/fields/StyleSetter/icons/background-repeat/NoRepeat.vue +20 -4
  195. package/src/fields/StyleSetter/icons/background-repeat/Repeat.vue +10 -28
  196. package/src/fields/StyleSetter/icons/background-repeat/RepeatX.vue +4 -5
  197. package/src/fields/StyleSetter/icons/background-repeat/RepeatY.vue +4 -5
  198. package/src/fields/StyleSetter/icons/flex-direction/Column.vue +4 -3
  199. package/src/fields/StyleSetter/icons/flex-direction/ColumnReverse.vue +4 -3
  200. package/src/fields/StyleSetter/icons/flex-direction/Row.vue +4 -3
  201. package/src/fields/StyleSetter/icons/flex-direction/RowReverse.vue +4 -3
  202. package/src/fields/StyleSetter/icons/justify-content/Center.vue +5 -2
  203. package/src/fields/StyleSetter/icons/justify-content/FlexEnd.vue +15 -2
  204. package/src/fields/StyleSetter/icons/justify-content/FlexStart.vue +15 -2
  205. package/src/fields/StyleSetter/icons/justify-content/SpaceAround.vue +28 -3
  206. package/src/fields/StyleSetter/icons/justify-content/SpaceBetween.vue +28 -2
  207. package/src/fields/StyleSetter/pro/Background.vue +99 -55
  208. package/src/fields/StyleSetter/pro/Border.vue +9 -11
  209. package/src/fields/StyleSetter/pro/Font.vue +66 -64
  210. package/src/fields/StyleSetter/pro/Layout.vue +211 -139
  211. package/src/fields/StyleSetter/pro/Position.vue +69 -67
  212. package/src/fields/StyleSetter/pro/Transform.vue +23 -25
  213. package/src/fields/UISelect.vue +0 -12
  214. package/src/hooks/index.ts +1 -0
  215. package/src/hooks/use-code-block-edit.ts +4 -3
  216. package/src/hooks/use-compare-form.ts +187 -0
  217. package/src/hooks/use-data-source-edit.ts +2 -2
  218. package/src/hooks/use-stage.ts +5 -3
  219. package/src/icons/DatasourceIcon.vue +7 -0
  220. package/src/index.ts +12 -0
  221. package/src/initService.ts +26 -16
  222. package/src/layouts/CodeEditor.vue +34 -11
  223. package/src/layouts/Framework.vue +15 -8
  224. package/src/layouts/NavMenu.vue +3 -3
  225. package/src/layouts/history-list/Bucket.vue +33 -41
  226. package/src/layouts/history-list/BucketTab.vue +72 -0
  227. package/src/layouts/history-list/GroupRow.vue +190 -93
  228. package/src/layouts/history-list/HistoryDiffDialog.vue +169 -90
  229. package/src/layouts/history-list/HistoryListPanel.vue +191 -95
  230. package/src/layouts/history-list/InitialRow.vue +38 -8
  231. package/src/layouts/history-list/PageTab.vue +67 -43
  232. package/src/layouts/history-list/composables.ts +239 -125
  233. package/src/layouts/history-list/useHistoryList.ts +60 -0
  234. package/src/layouts/history-list/useHistoryRevert.ts +425 -0
  235. package/src/layouts/page-bar/PageBar.vue +4 -2
  236. package/src/layouts/props-panel/FormPanel.vue +72 -6
  237. package/src/layouts/props-panel/PropsPanel.vue +62 -18
  238. package/src/layouts/props-panel/use-style-panel.ts +4 -3
  239. package/src/layouts/sidebar/ComponentListPanel.vue +10 -6
  240. package/src/layouts/sidebar/Sidebar.vue +13 -6
  241. package/src/layouts/sidebar/code-block/CodeBlockList.vue +5 -5
  242. package/src/layouts/sidebar/code-block/CodeBlockListPanel.vue +5 -2
  243. package/src/layouts/sidebar/code-block/useContentMenu.ts +14 -2
  244. package/src/layouts/sidebar/data-source/DataSourceConfigPanel.vue +34 -2
  245. package/src/layouts/sidebar/data-source/DataSourceListPanel.vue +29 -4
  246. package/src/layouts/sidebar/data-source/useContentMenu.ts +14 -2
  247. package/src/layouts/sidebar/layer/LayerMenu.vue +21 -13
  248. package/src/layouts/sidebar/layer/LayerNodeContent.vue +57 -0
  249. package/src/layouts/sidebar/layer/LayerNodeTool.vue +7 -4
  250. package/src/layouts/sidebar/layer/LayerPanel.vue +4 -1
  251. package/src/layouts/sidebar/layer/use-click.ts +3 -3
  252. package/src/layouts/sidebar/layer/use-node-status.ts +2 -2
  253. package/src/layouts/workspace/viewer/NodeListMenu.vue +4 -1
  254. package/src/layouts/workspace/viewer/Stage.vue +1 -1
  255. package/src/layouts/workspace/viewer/ViewerMenu.vue +15 -15
  256. package/src/plugin.ts +6 -3
  257. package/src/services/codeBlock.ts +152 -47
  258. package/src/services/dataSource.ts +120 -41
  259. package/src/services/dep.ts +292 -47
  260. package/src/services/editor.ts +820 -224
  261. package/src/services/history.ts +449 -412
  262. package/src/services/keybinding.ts +6 -6
  263. package/src/services/ui.ts +33 -5
  264. package/src/theme/code-block.scss +37 -0
  265. package/src/theme/common/var.scss +1 -1
  266. package/src/theme/component-list-panel.scss +2 -2
  267. package/src/theme/data-source-field.scss +4 -0
  268. package/src/theme/display-conds.scss +11 -0
  269. package/src/theme/event.scss +70 -1
  270. package/src/theme/floating-box.scss +9 -1
  271. package/src/theme/framework.scss +4 -1
  272. package/src/theme/history-list-panel.scss +157 -23
  273. package/src/theme/layer-node-content.scss +14 -0
  274. package/src/theme/nav-menu.scss +5 -1
  275. package/src/theme/page-bar.scss +0 -4
  276. package/src/theme/props-panel.scss +5 -4
  277. package/src/theme/scroll-bar.scss +64 -0
  278. package/src/theme/style-setter/border.scss +17 -5
  279. package/src/theme/theme.scss +4 -0
  280. package/src/theme/themes/magic-admin/index.scss +214 -0
  281. package/src/theme/ui-select.scss +9 -0
  282. package/src/type.ts +668 -124
  283. package/src/utils/config.ts +9 -1
  284. package/src/utils/const.ts +3 -2
  285. package/src/utils/content-menu.ts +20 -11
  286. package/src/utils/data-source/index.ts +32 -12
  287. package/src/utils/dep/collect-worker-client.ts +149 -0
  288. package/src/utils/dep/idle-task.ts +72 -35
  289. package/src/utils/dep/worker.ts +113 -9
  290. package/src/utils/editor.ts +166 -60
  291. package/src/utils/event.ts +224 -0
  292. package/src/utils/history.ts +286 -0
  293. package/src/utils/index.ts +4 -0
  294. package/src/utils/indexed-db.ts +122 -0
  295. package/src/utils/monaco-editor.ts +27 -0
  296. package/src/utils/operator.ts +2 -2
  297. package/src/utils/props.ts +114 -11
  298. package/src/utils/type-match-rules.ts +684 -0
  299. package/src/utils/undo-redo.ts +88 -0
  300. package/types/index.d.ts +1979 -515
  301. package/dist/es/layouts/history-list/CodeBlockTab.js +0 -5
  302. package/dist/es/layouts/history-list/CodeBlockTab.vue_vue_type_script_setup_true_lang.js +0 -62
  303. package/dist/es/layouts/history-list/DataSourceTab.js +0 -5
  304. package/dist/es/layouts/history-list/DataSourceTab.vue_vue_type_script_setup_true_lang.js +0 -62
  305. package/src/layouts/history-list/CodeBlockTab.vue +0 -61
  306. package/src/layouts/history-list/DataSourceTab.vue +0 -61
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.8.0-beta.2",
2
+ "version": "1.8.0-beta.20",
3
3
  "name": "@tmagic/editor",
4
4
  "type": "module",
5
5
  "sideEffects": [
@@ -58,11 +58,11 @@
58
58
  "moveable": "^0.53.0",
59
59
  "serialize-javascript": "^7.0.0",
60
60
  "sortablejs": "^1.15.6",
61
- "@tmagic/design": "1.8.0-beta.2",
62
- "@tmagic/table": "1.8.0-beta.2",
63
- "@tmagic/utils": "1.8.0-beta.2",
64
- "@tmagic/form": "1.8.0-beta.2",
65
- "@tmagic/stage": "1.8.0-beta.2"
61
+ "@tmagic/design": "1.8.0-beta.20",
62
+ "@tmagic/form": "1.8.0-beta.20",
63
+ "@tmagic/stage": "1.8.0-beta.20",
64
+ "@tmagic/table": "1.8.0-beta.20",
65
+ "@tmagic/utils": "1.8.0-beta.20"
66
66
  },
67
67
  "devDependencies": {
68
68
  "@types/events": "^3.0.3",
@@ -75,8 +75,8 @@
75
75
  "monaco-editor": "^0.55.1 ",
76
76
  "type-fest": "^5.2.0",
77
77
  "typescript": "^6.0.3",
78
- "vue": "^3.5.34",
79
- "@tmagic/core": "1.8.0-beta.2"
78
+ "vue": "^3.5.40",
79
+ "@tmagic/core": "1.8.0-beta.20"
80
80
  },
81
81
  "peerDependenciesMeta": {
82
82
  "typescript": {
package/src/Editor.vue CHANGED
@@ -4,6 +4,7 @@
4
4
  :page-bar-sort-options="pageBarSortOptions"
5
5
  :page-filter-function="pageFilterFunction"
6
6
  :hide-sidebar="hideSidebar"
7
+ :theme="theme"
7
8
  >
8
9
  <template #header>
9
10
  <slot name="header"></slot>
@@ -135,9 +136,10 @@
135
136
  <script lang="ts" setup>
136
137
  import { EventEmitter } from 'events';
137
138
 
138
- import { provide } from 'vue';
139
+ import { computed, provide, ref } from 'vue';
139
140
 
140
141
  import type { MApp } from '@tmagic/core';
142
+ import { M_THEME_KEY } from '@tmagic/design';
141
143
 
142
144
  import Framework from './layouts/Framework.vue';
143
145
  import TMagicNavMenu from './layouts/NavMenu.vue';
@@ -158,7 +160,7 @@ import stageOverlayService from './services/stageOverlay';
158
160
  import storageService from './services/storage';
159
161
  import uiService from './services/ui';
160
162
  import keybindingConfig from './utils/keybinding-config';
161
- import { defaultEditorProps, EditorProps } from './editorProps';
163
+ import { defaultEditorProps, EditorProps, ENABLE_PROPS_FORM_VALIDATE } from './editorProps';
162
164
  import { initServiceEvents, initServiceState } from './initService';
163
165
  import type { TreeNodeData } from './type';
164
166
  import type { EditorSlots, EventBus, Services, StageOptions } from './type';
@@ -216,20 +218,26 @@ const stageOptions: StageOptions = {
216
218
  containerHighlightClassName: props.containerHighlightClassName,
217
219
  containerHighlightDuration: props.containerHighlightDuration,
218
220
  containerHighlightType: props.containerHighlightType,
221
+ containerHighlightAddOnly: props.containerHighlightAddOnly,
219
222
  disabledDragStart: props.disabledDragStart,
220
223
  renderType: props.renderType,
221
224
  guidesOptions: props.guidesOptions,
222
225
  disabledMultiSelect: props.disabledMultiSelect,
223
226
  alwaysMultiSelect: props.alwaysMultiSelect,
227
+ disabledFlashTip: props.disabledFlashTip,
224
228
  beforeDblclick: props.beforeDblclick,
225
229
  };
226
230
 
227
231
  stageOverlayService.set('stageOptions', stageOptions);
228
232
 
233
+ const propsPanelRef = ref<InstanceType<typeof FormPanel> | null>(null);
234
+
229
235
  provide('services', services);
230
236
 
231
237
  provide('codeOptions', props.codeOptions);
232
238
  provide('stageOptions', stageOptions);
239
+ /** 是否启用「属性配置表单校验」联动能力,供 PropsPanel / FormPanel 判断校验失败时是否仍更新节点并记录错误 */
240
+ provide(ENABLE_PROPS_FORM_VALIDATE, props.enablePropsFormValidate ?? false);
233
241
  /**
234
242
  * 把顶层 `extendFormState` 提供给非 PropsPanel 链路上的组件使用(例如历史差异对话框 HistoryDiffDialog
235
243
  * 内部的 CompareForm)。这样所有依赖业务上下文的表单 filterFunction 都能拿到一致的扩展状态,
@@ -237,12 +245,45 @@ provide('stageOptions', stageOptions);
237
245
  */
238
246
  provide('extendFormState', props.extendFormState);
239
247
 
248
+ // 用 computed 包一层再 provide,否则传下去的是 provide 那一刻的值快照,
249
+ // props.isLargeStageContainer 后续变化不会同步到子孙(如 @tmagic/design/ColorPicker)。
250
+ // 子孙侧 `inject<ComputedRef<boolean>>('isLargeStageContainer', computed(() => false))`
251
+ // 用 `.value` 或模板自动解包读取即可拿到最新值。
252
+ provide(
253
+ 'isLargeStageContainer',
254
+ computed(() => props.isLargeStageContainer),
255
+ );
256
+ /**
257
+ * 提供 PropsPanel 主属性表单的 formState getter,供历史差异弹窗复用,
258
+ * 让 CompareForm 与 PropsPanel 的 filterFunction 上下文保持一致。
259
+ */
260
+ provide('getPropsPanelFormState', () => propsPanelRef.value?.configForm?.formState);
261
+
262
+ /**
263
+ * 把历史记录面板的自定义扩展 tab 提供给深层的 HistoryListPanel(它挂在 NavMenu 中,
264
+ * 以 markRaw component 形式渲染,无法直接通过 props 透传)。业务方可借此在历史记录
265
+ * 面板内追加自定义模块的历史 tab。
266
+ */
267
+ provide('historyListExtraTabs', props.historyListExtraTabs);
268
+
240
269
  provide<EventBus>('eventBus', new EventEmitter());
241
270
 
271
+ /**
272
+ * 把当前主题以响应式 ref 形式 provide 给后代,供包含 `Teleport` 的组件
273
+ * (如 `TMagicPopover` / `FloatingBox` / `ContentMenu`)在传送目标上挂 `m-theme--<theme>`
274
+ * 类,让主题级 CSS 变量在 portal 节点上也能命中。详见 `@tmagic/design/theme.ts`。
275
+ */
276
+ provide(
277
+ M_THEME_KEY,
278
+ computed(() => props.theme ?? ''),
279
+ );
280
+
242
281
  const propsPanelMountedHandler = (e: InstanceType<typeof FormPanel>) => {
282
+ propsPanelRef.value = e;
243
283
  emit('props-panel-mounted', e);
244
284
  };
245
285
  const propsPanelUnmountedHandler = () => {
286
+ propsPanelRef.value = null;
246
287
  emit('props-panel-unmounted');
247
288
  };
248
289
 
@@ -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(() => {
@@ -10,101 +10,45 @@
10
10
  :is-compare="true"
11
11
  :disabled="true"
12
12
  :label-width="labelWidth"
13
- :extend-state="extendState"
13
+ :extend-state="mergedExtendState"
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, 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 { getCodeBlockFormConfig } from '@editor/utils/code-block';
28
+ import { useCompareForm } from '@editor/hooks/use-compare-form';
29
+ import type { CompareFormBaseProps } from '@editor/type';
28
30
 
29
31
  defineOptions({
30
32
  name: 'MEditorCompareForm',
31
33
  });
32
34
 
33
- /**
34
- * 对比类型:
35
- * - node: 节点组件,按 `type` 从 propsService 获取属性表单配置
36
- * - data-source: 数据源,按 `type`(base/http/...) 从 dataSourceService 获取数据源表单配置
37
- * - code-block: 数据源代码块,使用内置的代码块表单配置
38
- */
39
- export type CompareCategory = 'node' | 'data-source' | 'code-block';
40
-
41
35
  const props = withDefaults(
42
- defineProps<{
43
- /** 当前值(修改后的值) */
44
- value: Partial<MNode> | Partial<DataSourceSchema> | Partial<CodeBlockContent> | Record<string, any>;
45
- /** 用于对比的旧值(修改前的值) */
46
- lastValue?: Partial<MNode> | Partial<DataSourceSchema> | Partial<CodeBlockContent> | Record<string, any>;
47
- /**
48
- * 类型说明:
49
- * - `category` 为 `node` 时,`type` 为节点组件的类型,例如 'text'、'button'、'page'、'container' 等
50
- * - `category` 为 `data-source` 时,`type` 为数据源类型,例如 'base'、'http'
51
- * - `category` 为 `code-block` 时,`type` 可不传
52
- */
53
- type?: string;
54
- /** 表单配置类别,决定从哪里取 FormConfig */
55
- category?: CompareCategory;
56
- /** 数据源代码块场景下的数据源类型(base/http),用于代码块表单中"执行时机"展示 */
57
- dataSourceType?: string;
58
- labelWidth?: string;
59
- /**
60
- * 外层容器高度。设置后表单内容超出时会在 CompareForm 内部出现滚动条,
61
- * 避免 dialog / 面板使用方需要自行处理滚动。可传任意 CSS 长度,例如 `60vh` / `400px` / `100%`。
62
- */
63
- height?: string;
64
- /**
65
- * 用户自定义注入到 MForm.formState 的扩展字段,与 Editor 顶层的 `extendFormState`、
66
- * PropsPanel 的 `extend-state` 语义一致。表单 item 的 `display` / `disabled` 等
67
- * filterFunction 经常依赖这里注入的字段(如 stage、自定义业务上下文等),
68
- * 因此在差异对比场景下也需要透传,避免出现 `formState.xxx is undefined` 的运行时错误。
69
- */
70
- extendState?: (_state: FormState) => Record<string, any> | Promise<Record<string, any>>;
71
- }>(),
36
+ defineProps<
37
+ CompareFormBaseProps & {
38
+ /** 用于对比的旧值(修改前的值) */
39
+ lastValue?: CompareFormBaseProps['value'];
40
+ /** 需要走 self diff 的字段类型(例如 mod-cond)。 */
41
+ selfDiffFieldTypes?: string[];
42
+ }
43
+ >(),
72
44
  {
73
45
  category: 'node',
74
46
  labelWidth: '120px',
75
47
  },
76
48
  );
77
49
 
78
- const { propsService, dataSourceService, codeBlockService, editorService } = useServices();
79
- const services = useServices();
80
-
81
- const config = ref<FormConfig>([]);
82
-
83
- /** vs-code 编辑器的 monaco 配置项,沿用 Editor 顶层 provide('codeOptions', ...) 的注入。 */
84
- const codeOptions = inject<Record<string, any>>('codeOptions', {});
85
-
86
- /** 将代码块的 content 字段统一成字符串,便于在表单/对比中展示 */
87
- const normalizeCodeBlockValue = (
88
- v: Partial<CodeBlockContent> | Record<string, any> | undefined,
89
- ): Record<string, any> => {
90
- if (!v) return {};
91
- const next: Record<string, any> = { ...v };
92
- if (next.content && typeof next.content !== 'string') {
93
- try {
94
- next.content = next.content.toString();
95
- } catch {
96
- next.content = '';
97
- }
98
- }
99
- return next;
100
- };
101
-
102
- const currentValues = computed<FormValue>(() => {
103
- if (props.category === 'code-block') {
104
- return normalizeCodeBlockValue(props.value as Partial<CodeBlockContent>);
105
- }
106
- return (props.value || {}) as FormValue;
107
- });
50
+ const { config, currentValues, wrapperStyle, mergedExtendState, loadConfig, formRef, normalizeCodeBlockValue } =
51
+ useCompareForm(props);
108
52
 
109
53
  const lastValuesProcessed = computed<FormValue>(() => {
110
54
  if (props.category === 'code-block') {
@@ -113,18 +57,6 @@ const lastValuesProcessed = computed<FormValue>(() => {
113
57
  return (props.lastValue || {}) as FormValue;
114
58
  });
115
59
 
116
- /**
117
- * 外层包裹层的样式:当传入 `height` 时启用固定高度 + 内部滚动,
118
- * 这样滚动条会出现在 CompareForm 内部,避免父容器(如 Dialog)自身也产生滚动。
119
- */
120
- const wrapperStyle = computed(() => {
121
- if (!props.height) return undefined;
122
- return {
123
- height: props.height,
124
- overflow: 'auto',
125
- } as Record<string, string>;
126
- });
127
-
128
60
  /**
129
61
  * `code-select` 字段在历史数据中存在两种"语义为空"的形态:
130
62
  * - 字符串 `''`(旧数据 / 用户从未配置过钩子);
@@ -153,66 +85,6 @@ const showDiff = ({ curValue, lastValue, config }: { curValue: any; lastValue: a
153
85
  return !isEqual(curValue, lastValue);
154
86
  };
155
87
 
156
- const loadConfig = async () => {
157
- switch (props.category) {
158
- case 'node': {
159
- if (!props.type) {
160
- config.value = [];
161
- return;
162
- }
163
- config.value = await propsService.getPropsConfig(props.type);
164
- break;
165
- }
166
- case 'data-source': {
167
- config.value = dataSourceService.getFormConfig(props.type || 'base');
168
- break;
169
- }
170
- case 'code-block': {
171
- config.value = getCodeBlockFormConfig({
172
- paramColConfig: codeBlockService.getParamsColConfig(),
173
- // 通过传入 dataSourceType 间接表达"是数据源代码块"——在对比场景下 props.dataSourceType
174
- // 由调用方按 step 上下文显式传入,未传则视为普通代码块,「执行时机」字段隐藏。
175
- isDataSource: () => Boolean(props.dataSourceType),
176
- dataSourceType: () => props.dataSourceType,
177
- codeOptions,
178
- // 对比模式只读,不需要校验/语法检查
179
- editable: false,
180
- });
181
- break;
182
- }
183
- default:
184
- config.value = [];
185
- }
186
- };
187
-
188
- watch(
189
- [() => props.category, () => props.type, () => props.dataSourceType],
190
- () => {
191
- loadConfig();
192
- },
193
- { immediate: true },
194
- );
195
-
196
- const formRef = useTemplateRef<InstanceType<typeof MForm>>('form');
197
-
198
- /**
199
- * 把 services / stage 注入 MForm 的 formState,避免 propsService 注入的表单配置中
200
- * 形如 `display: ({ services }) => services.uiService.get(...)` 的 filterFunction
201
- * 在执行时拿不到 `formState.services` 而报错。
202
- *
203
- * 与 props-panel/FormPanel.vue 中的注入方式保持一致:
204
- * - services:整个 useServices() 返回的服务集合;
205
- * - stage:当前 editorService.get('stage') 的最新值。
206
- */
207
- const stage = computed(() => editorService.get('stage'));
208
-
209
- watchEffect(() => {
210
- if (formRef.value) {
211
- formRef.value.formState.stage = stage.value;
212
- formRef.value.formState.services = services;
213
- }
214
- });
215
-
216
88
  defineExpose<{
217
89
  form: ShallowRef<InstanceType<typeof MForm> | null>;
218
90
  config: Ref<FormConfig>;
@@ -2,8 +2,8 @@
2
2
  <transition name="fade">
3
3
  <div
4
4
  v-show="visible"
5
- class="magic-editor-content-menu"
6
5
  ref="menu"
6
+ :class="['magic-editor-content-menu', themeClass]"
7
7
  :style="menuStyle"
8
8
  @mouseenter="mouseenterHandler()"
9
9
  @contextmenu.prevent
@@ -39,7 +39,7 @@
39
39
  <script lang="ts" setup>
40
40
  import { computed, nextTick, onBeforeUnmount, onMounted, type Ref, ref, useTemplateRef } from 'vue';
41
41
 
42
- import { useZIndex } from '@tmagic/design';
42
+ import { useThemeClass, useZIndex } from '@tmagic/design';
43
43
 
44
44
  import { MenuButton, MenuComponent } from '@editor/type';
45
45
 
@@ -73,6 +73,14 @@ const menuEl = useTemplateRef<HTMLDivElement>('menu');
73
73
  const buttonRefs = useTemplateRef<InstanceType<typeof ToolButton>[]>('buttons');
74
74
  const subMenuRef = useTemplateRef<any>('subMenu');
75
75
  const visible = ref(false);
76
+
77
+ /**
78
+ * 主题修饰类(来自最近的 `<MEditor>` / `<MForm>` 祖先 provide)。
79
+ * - 顶层 `ContentMenu` 渲染在编辑器子树中,加上去是冗余但无害;
80
+ * - 子菜单(递归 `<content-menu :is-sub-menu="true">` 被 `<teleport to="body">` 送到 body)
81
+ * 不在编辑器子树中,必须显式挂上主题类,主题级 CSS 变量才能命中。
82
+ */
83
+ const themeClass = useThemeClass();
76
84
  const subMenuData: Ref<(MenuButton | MenuComponent)[]> = ref<(MenuButton | MenuComponent)[]>([]);
77
85
  const zIndex = useZIndex();
78
86
  const curZIndex = ref<number>(0);
@@ -120,20 +128,42 @@ const outsideClickHideHandler = (e: MouseEvent) => {
120
128
  hide();
121
129
  };
122
130
 
123
- const setPosition = (e: { clientY: number; clientX: number }) => {
124
- 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;
125
140
 
126
- let top = e.clientY;
127
- if (menuHeight + e.clientY > document.body.clientHeight) {
128
- top = document.body.clientHeight - menuHeight;
141
+ if (top + menuHeight > document.body.clientHeight) {
142
+ top = Math.max(0, document.body.clientHeight - menuHeight);
129
143
  }
130
144
 
145
+ if (left + menuWidth > document.body.clientWidth) {
146
+ left = Math.max(0, document.body.clientWidth - menuWidth);
147
+ }
148
+
149
+ if (top !== menuPosition.value.top || left !== menuPosition.value.left) {
150
+ menuPosition.value = { top, left };
151
+ }
152
+ };
153
+
154
+ const setPosition = (e: { clientY: number; clientX: number }) => {
131
155
  menuPosition.value = {
132
- top,
156
+ top: e.clientY,
133
157
  left: e.clientX,
134
158
  };
159
+ fixPosition();
135
160
  };
136
161
 
162
+ // 菜单大小动态变化(如菜单项更新)后重新修正位置
163
+ const resizeObserver = new ResizeObserver(() => {
164
+ fixPosition();
165
+ });
166
+
137
167
  const show = (e?: { clientY: number; clientX: number }) => {
138
168
  visible.value = true;
139
169
 
@@ -178,12 +208,18 @@ const mouseenterHandler = () => {
178
208
  };
179
209
 
180
210
  onMounted(() => {
211
+ if (menuEl.value) {
212
+ resizeObserver.observe(menuEl.value);
213
+ }
214
+
181
215
  if (props.isSubMenu) return;
182
216
 
183
217
  globalThis.addEventListener('mousedown', outsideClickHideHandler, true);
184
218
  });
185
219
 
186
220
  onBeforeUnmount(() => {
221
+ resizeObserver.disconnect();
222
+
187
223
  if (props.isSubMenu) return;
188
224
 
189
225
  globalThis.removeEventListener('mousedown', outsideClickHideHandler, true);
@@ -1,6 +1,12 @@
1
1
  <template>
2
2
  <Teleport to="body" v-if="visible">
3
- <div ref="target" class="m-editor-float-box" :style="{ ...style, zIndex: curZIndex }" @mousedown="nextZIndex">
3
+ <div
4
+ ref="target"
5
+ :class="['m-editor-float-box', themeClass]"
6
+ v-bind="$attrs"
7
+ :style="{ ...style, zIndex: curZIndex }"
8
+ @mousedown="nextZIndex"
9
+ >
4
10
  <div ref="title" class="m-editor-float-box-title">
5
11
  <slot name="title">
6
12
  <span>{{ title }}</span>
@@ -9,7 +15,7 @@
9
15
  <TMagicButton link size="small" @click="closeHandler"><MIcon :icon="Close"></MIcon></TMagicButton>
10
16
  </div>
11
17
  </div>
12
- <div class="m-editor-float-box-body" :style="{ height: `${bodyHeight}px` }">
18
+ <div class="m-editor-float-box-body" :style="{ height: `${bodyHeight}px`, ...bodyStyle }">
13
19
  <slot name="body"></slot>
14
20
  </div>
15
21
  </div>
@@ -17,14 +23,13 @@
17
23
  </template>
18
24
 
19
25
  <script setup lang="ts">
20
- import { computed, nextTick, onBeforeUnmount, provide, ref, useTemplateRef, watch } from 'vue';
26
+ import { computed, type CSSProperties, nextTick, onBeforeUnmount, provide, ref, useTemplateRef, watch } from 'vue';
21
27
  import { Close } from '@element-plus/icons-vue';
22
28
  import VanillaMoveable from 'moveable';
23
29
 
24
- import { TMagicButton, useZIndex } from '@tmagic/design';
30
+ import { TMagicButton, useThemeClass, useZIndex } from '@tmagic/design';
25
31
 
26
32
  import MIcon from '@editor/components/Icon.vue';
27
- import { useServices } from '@editor/hooks/use-services';
28
33
 
29
34
  interface Position {
30
35
  left: number;
@@ -39,17 +44,30 @@ const props = withDefaults(
39
44
  defineProps<{
40
45
  position?: Position;
41
46
  title?: string;
47
+ bodyStyle?: CSSProperties;
48
+ /** 浮窗初始样式,会与内部计算样式合并,外部传入优先 */
49
+ initialStyle?: CSSProperties;
50
+ /** 用于约束浮窗 left 的容器宽度,传入时按宽度收敛 left,避免超出右边界;默认取视窗宽度 */
51
+ frameworkWidth?: number;
42
52
  beforeClose?: (_done: (_cancel?: boolean) => void) => void;
43
53
  }>(),
44
54
  {
45
55
  title: '',
46
56
  position: () => ({ left: 0, top: 0 }),
57
+ initialStyle: () => ({}),
58
+ frameworkWidth: 0,
47
59
  },
48
60
  );
49
61
 
50
62
  const targetEl = useTemplateRef<HTMLDivElement>('target');
51
63
  const titleEl = useTemplateRef<HTMLDivElement>('title');
52
64
 
65
+ /**
66
+ * 主题修饰类(来自最近的 `<MEditor>` / `<MForm>` 祖先 provide)。
67
+ * 挂在 `Teleport` 出去的浮动面板根节点上,让主题级 CSS 变量在 portal 节点上也能命中。
68
+ */
69
+ const themeClass = useThemeClass();
70
+
53
71
  const zIndex = useZIndex();
54
72
  const curZIndex = ref<number>(0);
55
73
 
@@ -66,12 +84,11 @@ const bodyHeight = computed(() => {
66
84
  return 'auto';
67
85
  });
68
86
 
69
- const { uiService } = useServices();
70
- const frameworkWidth = computed(() => uiService.get('frameworkRect').width || 0);
71
87
  const style = computed(() => {
72
88
  let { left } = props.position;
73
- if (width.value) {
74
- 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;
75
92
  }
76
93
 
77
94
  return {
@@ -79,11 +96,60 @@ const style = computed(() => {
79
96
  top: `${props.position.top}px`,
80
97
  width: width.value ? `${width.value}px` : 'auto',
81
98
  height: height.value ? `${height.value}px` : 'auto',
99
+ ...props.initialStyle,
82
100
  };
83
101
  });
84
102
 
85
103
  let moveable: VanillaMoveable | null = null;
86
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
+
87
153
  const initMoveable = () => {
88
154
  moveable = new VanillaMoveable(globalThis.document.body, {
89
155
  className: 'm-editor-floating-box-moveable',
@@ -101,6 +167,14 @@ const initMoveable = () => {
101
167
  bounds: { left: 0, top: 0, right: 0, bottom: 0, position: 'css' },
102
168
  });
103
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
+
104
178
  moveable.on('drag', (e) => {
105
179
  e.target.style.transform = e.transform;
106
180
  });
@@ -115,6 +189,7 @@ const initMoveable = () => {
115
189
  };
116
190
 
117
191
  const destroyMoveable = () => {
192
+ hideDragMask();
118
193
  moveable?.destroy();
119
194
  moveable = null;
120
195
  };