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

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 (308) 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 +156 -155
  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/events.js +2 -2
  138. package/dist/es/services/history.js +350 -386
  139. package/dist/es/services/keybinding.js +6 -6
  140. package/dist/es/services/props.js +3 -2
  141. package/dist/es/services/storage.js +2 -2
  142. package/dist/es/services/ui.js +10 -2
  143. package/dist/es/style.css +549 -113
  144. package/dist/es/utils/config.js +4 -1
  145. package/dist/es/utils/const.js +2 -2
  146. package/dist/es/utils/content-menu.js +19 -11
  147. package/dist/es/utils/data-source/index.js +34 -11
  148. package/dist/es/utils/dep/collect-worker-client.js +114 -0
  149. package/dist/es/utils/dep/idle-task.js +70 -22
  150. package/dist/es/utils/dep/worker.js +1 -1
  151. package/dist/es/utils/editor.js +103 -49
  152. package/dist/es/utils/event.js +135 -0
  153. package/dist/es/utils/history.js +220 -0
  154. package/dist/es/utils/indexed-db.js +86 -0
  155. package/dist/es/utils/monaco-editor.js +22 -6
  156. package/dist/es/utils/operator.js +2 -2
  157. package/dist/es/utils/props.js +114 -33
  158. package/dist/es/utils/type-match-rules.js +367 -0
  159. package/dist/es/utils/undo-redo.js +60 -1
  160. package/dist/style.css +549 -113
  161. package/dist/themes/magic-admin.css +3028 -0
  162. package/dist/tmagic-editor.umd.cjs +14403 -10121
  163. package/package.json +8 -8
  164. package/src/Editor.vue +43 -2
  165. package/src/components/CodeBlockEditor.vue +3 -0
  166. package/src/components/CompareForm.vue +18 -146
  167. package/src/components/ContentMenu.vue +44 -8
  168. package/src/components/FloatingBox.vue +84 -9
  169. package/src/components/ScrollBar.vue +0 -67
  170. package/src/components/ToolButton.vue +2 -2
  171. package/src/components/ViewForm.vue +55 -0
  172. package/src/editorProps.ts +30 -0
  173. package/src/fields/Code.vue +10 -2
  174. package/src/fields/CodeLink.vue +2 -5
  175. package/src/fields/CodeSelect.vue +54 -40
  176. package/src/fields/CodeSelectCol.vue +8 -1
  177. package/src/fields/CondOpSelect.vue +2 -24
  178. package/src/fields/DataSourceFieldSelect/FieldSelect.vue +16 -2
  179. package/src/fields/DataSourceFieldSelect/Index.vue +14 -5
  180. package/src/fields/DataSourceFields.vue +42 -8
  181. package/src/fields/DataSourceInput.vue +10 -28
  182. package/src/fields/DataSourceMethodSelect.vue +9 -4
  183. package/src/fields/DataSourceMethods.vue +42 -21
  184. package/src/fields/DataSourceMocks.vue +3 -0
  185. package/src/fields/DisplayConds.vue +18 -1
  186. package/src/fields/EventSelect.vue +152 -166
  187. package/src/fields/StyleSetter/Index.vue +3 -12
  188. package/src/fields/StyleSetter/components/Border.vue +15 -6
  189. package/src/fields/StyleSetter/icons/align-items/Center.vue +19 -0
  190. package/src/fields/StyleSetter/icons/align-items/FlexEnd.vue +19 -0
  191. package/src/fields/StyleSetter/icons/align-items/FlexStart.vue +19 -0
  192. package/src/fields/StyleSetter/icons/align-items/SpaceAround.vue +34 -0
  193. package/src/fields/StyleSetter/icons/align-items/SpaceBetween.vue +34 -0
  194. package/src/fields/StyleSetter/icons/align-items/index.ts +5 -0
  195. package/src/fields/StyleSetter/icons/background-repeat/NoRepeat.vue +20 -4
  196. package/src/fields/StyleSetter/icons/background-repeat/Repeat.vue +10 -28
  197. package/src/fields/StyleSetter/icons/background-repeat/RepeatX.vue +4 -5
  198. package/src/fields/StyleSetter/icons/background-repeat/RepeatY.vue +4 -5
  199. package/src/fields/StyleSetter/icons/flex-direction/Column.vue +4 -3
  200. package/src/fields/StyleSetter/icons/flex-direction/ColumnReverse.vue +4 -3
  201. package/src/fields/StyleSetter/icons/flex-direction/Row.vue +4 -3
  202. package/src/fields/StyleSetter/icons/flex-direction/RowReverse.vue +4 -3
  203. package/src/fields/StyleSetter/icons/justify-content/Center.vue +5 -2
  204. package/src/fields/StyleSetter/icons/justify-content/FlexEnd.vue +15 -2
  205. package/src/fields/StyleSetter/icons/justify-content/FlexStart.vue +15 -2
  206. package/src/fields/StyleSetter/icons/justify-content/SpaceAround.vue +28 -3
  207. package/src/fields/StyleSetter/icons/justify-content/SpaceBetween.vue +28 -2
  208. package/src/fields/StyleSetter/pro/Background.vue +99 -55
  209. package/src/fields/StyleSetter/pro/Border.vue +9 -11
  210. package/src/fields/StyleSetter/pro/Font.vue +66 -64
  211. package/src/fields/StyleSetter/pro/Layout.vue +211 -139
  212. package/src/fields/StyleSetter/pro/Position.vue +69 -67
  213. package/src/fields/StyleSetter/pro/Transform.vue +23 -25
  214. package/src/fields/UISelect.vue +0 -12
  215. package/src/hooks/index.ts +1 -0
  216. package/src/hooks/use-code-block-edit.ts +4 -3
  217. package/src/hooks/use-compare-form.ts +187 -0
  218. package/src/hooks/use-data-source-edit.ts +2 -2
  219. package/src/hooks/use-stage.ts +5 -3
  220. package/src/icons/DatasourceIcon.vue +7 -0
  221. package/src/index.ts +12 -0
  222. package/src/initService.ts +26 -16
  223. package/src/layouts/CodeEditor.vue +34 -11
  224. package/src/layouts/Framework.vue +15 -8
  225. package/src/layouts/NavMenu.vue +3 -3
  226. package/src/layouts/history-list/Bucket.vue +33 -41
  227. package/src/layouts/history-list/BucketTab.vue +72 -0
  228. package/src/layouts/history-list/GroupRow.vue +190 -93
  229. package/src/layouts/history-list/HistoryDiffDialog.vue +169 -90
  230. package/src/layouts/history-list/HistoryListPanel.vue +191 -95
  231. package/src/layouts/history-list/InitialRow.vue +38 -8
  232. package/src/layouts/history-list/PageTab.vue +67 -43
  233. package/src/layouts/history-list/composables.ts +239 -125
  234. package/src/layouts/history-list/useHistoryList.ts +60 -0
  235. package/src/layouts/history-list/useHistoryRevert.ts +425 -0
  236. package/src/layouts/page-bar/PageBar.vue +4 -2
  237. package/src/layouts/props-panel/FormPanel.vue +72 -6
  238. package/src/layouts/props-panel/PropsPanel.vue +62 -18
  239. package/src/layouts/props-panel/use-style-panel.ts +4 -3
  240. package/src/layouts/sidebar/ComponentListPanel.vue +10 -6
  241. package/src/layouts/sidebar/Sidebar.vue +13 -6
  242. package/src/layouts/sidebar/code-block/CodeBlockList.vue +5 -5
  243. package/src/layouts/sidebar/code-block/CodeBlockListPanel.vue +5 -2
  244. package/src/layouts/sidebar/code-block/useContentMenu.ts +14 -2
  245. package/src/layouts/sidebar/data-source/DataSourceConfigPanel.vue +34 -2
  246. package/src/layouts/sidebar/data-source/DataSourceListPanel.vue +29 -4
  247. package/src/layouts/sidebar/data-source/useContentMenu.ts +14 -2
  248. package/src/layouts/sidebar/layer/LayerMenu.vue +21 -13
  249. package/src/layouts/sidebar/layer/LayerNodeContent.vue +57 -0
  250. package/src/layouts/sidebar/layer/LayerNodeTool.vue +7 -4
  251. package/src/layouts/sidebar/layer/LayerPanel.vue +4 -1
  252. package/src/layouts/sidebar/layer/use-click.ts +3 -3
  253. package/src/layouts/sidebar/layer/use-node-status.ts +2 -2
  254. package/src/layouts/workspace/viewer/NodeListMenu.vue +4 -1
  255. package/src/layouts/workspace/viewer/Stage.vue +1 -1
  256. package/src/layouts/workspace/viewer/ViewerMenu.vue +15 -15
  257. package/src/plugin.ts +6 -3
  258. package/src/services/codeBlock.ts +152 -47
  259. package/src/services/dataSource.ts +120 -41
  260. package/src/services/dep.ts +292 -47
  261. package/src/services/editor.ts +820 -224
  262. package/src/services/events.ts +3 -3
  263. package/src/services/history.ts +449 -412
  264. package/src/services/keybinding.ts +6 -6
  265. package/src/services/ui.ts +33 -5
  266. package/src/theme/code-block.scss +37 -0
  267. package/src/theme/common/var.scss +1 -1
  268. package/src/theme/component-list-panel.scss +2 -2
  269. package/src/theme/data-source-field.scss +4 -0
  270. package/src/theme/display-conds.scss +11 -0
  271. package/src/theme/event.scss +70 -1
  272. package/src/theme/floating-box.scss +9 -1
  273. package/src/theme/framework.scss +4 -1
  274. package/src/theme/history-list-panel.scss +157 -23
  275. package/src/theme/layer-node-content.scss +14 -0
  276. package/src/theme/nav-menu.scss +5 -1
  277. package/src/theme/page-bar.scss +0 -4
  278. package/src/theme/props-panel.scss +5 -4
  279. package/src/theme/scroll-bar.scss +64 -0
  280. package/src/theme/style-setter/border.scss +17 -5
  281. package/src/theme/theme.scss +4 -0
  282. package/src/theme/themes/magic-admin/index.scss +214 -0
  283. package/src/theme/ui-select.scss +9 -0
  284. package/src/type.ts +668 -124
  285. package/src/utils/config.ts +9 -1
  286. package/src/utils/const.ts +3 -2
  287. package/src/utils/content-menu.ts +20 -11
  288. package/src/utils/data-source/index.ts +32 -12
  289. package/src/utils/dep/collect-worker-client.ts +149 -0
  290. package/src/utils/dep/idle-task.ts +104 -35
  291. package/src/utils/dep/worker.ts +113 -9
  292. package/src/utils/editor.ts +166 -60
  293. package/src/utils/event.ts +237 -0
  294. package/src/utils/history.ts +286 -0
  295. package/src/utils/index.ts +4 -0
  296. package/src/utils/indexed-db.ts +122 -0
  297. package/src/utils/monaco-editor.ts +27 -0
  298. package/src/utils/operator.ts +2 -2
  299. package/src/utils/props.ts +114 -11
  300. package/src/utils/type-match-rules.ts +684 -0
  301. package/src/utils/undo-redo.ts +88 -0
  302. package/types/index.d.ts +1990 -517
  303. package/dist/es/layouts/history-list/CodeBlockTab.js +0 -5
  304. package/dist/es/layouts/history-list/CodeBlockTab.vue_vue_type_script_setup_true_lang.js +0 -62
  305. package/dist/es/layouts/history-list/DataSourceTab.js +0 -5
  306. package/dist/es/layouts/history-list/DataSourceTab.vue_vue_type_script_setup_true_lang.js +0 -62
  307. package/src/layouts/history-list/CodeBlockTab.vue +0 -61
  308. package/src/layouts/history-list/DataSourceTab.vue +0 -61
@@ -16,14 +16,22 @@
16
16
  * limitations under the License.
17
17
  */
18
18
 
19
+ import { ref } from 'vue';
20
+
19
21
  import { EditorInstallOptions } from '@editor/type';
20
22
 
21
23
  let $TMAGIC_EDITOR: EditorInstallOptions = {} as any;
22
24
 
25
+ // 用 ref 持有 flat 全局开关:const 引用本身不可变,符合 `import/no-mutable-exports`;
26
+ // 通过 `.value` 改值仍保持模块级响应式语义,与 editor/plugin.ts、design/index.ts 里
27
+ // 的同名变量写法对齐。
28
+ const isGlobalFlat = ref(false);
29
+
23
30
  const setEditorConfig = (option: EditorInstallOptions): void => {
24
31
  $TMAGIC_EDITOR = option;
32
+ isGlobalFlat.value = option.flat ?? false;
25
33
  };
26
34
 
27
35
  const getEditorConfig = <K extends keyof EditorInstallOptions>(key: K): EditorInstallOptions[K] => $TMAGIC_EDITOR[key];
28
36
 
29
- export { getEditorConfig, setEditorConfig };
37
+ export { getEditorConfig, isGlobalFlat, setEditorConfig };
@@ -5,10 +5,11 @@ export const LEFT_COLUMN_WIDTH_STORAGE_KEY = '$MagicEditorLeftColumnWidthData';
5
5
  export const RIGHT_COLUMN_WIDTH_STORAGE_KEY = '$MagicEditorRightColumnWidthData';
6
6
  export const PROPS_PANEL_WIDTH_STORAGE_KEY = '$MagicEditorPropsPanelWidthData';
7
7
 
8
- export const DEFAULT_LEFT_COLUMN_WIDTH = 310;
8
+ export const DEFAULT_LEFT_COLUMN_WIDTH = 345;
9
9
  export const DEFAULT_RIGHT_COLUMN_WIDTH = 480;
10
10
 
11
- export const MIN_LEFT_COLUMN_WIDTH = 200;
11
+ // 2026-06-11 设计稿修改,固定左侧栏存在时最小宽度为 345
12
+ export const MIN_LEFT_COLUMN_WIDTH = 345;
12
13
  export const MIN_CENTER_COLUMN_WIDTH = 400;
13
14
  export const MIN_RIGHT_COLUMN_WIDTH = 300;
14
15
 
@@ -2,24 +2,29 @@ import { computed, markRaw, type ShallowRef } from 'vue';
2
2
  import { CopyDocument, Delete, DocumentCopy } from '@element-plus/icons-vue';
3
3
 
4
4
  import { cloneDeep, Id, MContainer, NodeType } from '@tmagic/core';
5
- import { calcValueByFontsize, isPage, isPageFragment } from '@tmagic/utils';
5
+ import { calcValueByFontsize, isPage, isPageOrFragment } from '@tmagic/utils';
6
6
 
7
7
  import ContentMenu from '@editor/components/ContentMenu.vue';
8
- import type { MenuButton, Services } from '@editor/type';
8
+ import type { HistoryOpSource, MenuButton, Services } from '@editor/type';
9
9
 
10
10
  import { COPY_STORAGE_KEY } from './editor';
11
11
 
12
- export const useDeleteMenu = (): MenuButton => ({
12
+ /**
13
+ * 共享的右键菜单项构造器(画布 ViewerMenu 与图层树 LayerMenu 共用)。
14
+ * `historySource` 用于标记本次操作的途径,调用方按所在面板传入:
15
+ * 画布传 `'stage-contextmenu'`,树形面板传 `'tree-contextmenu'`。
16
+ */
17
+ export const useDeleteMenu = (historySource?: HistoryOpSource): MenuButton => ({
13
18
  type: 'button',
14
19
  text: '删除',
15
20
  icon: Delete,
16
21
  display: ({ editorService }) => {
17
22
  const node = editorService.get('node');
18
- return node?.type !== NodeType.ROOT && !isPage(node) && !isPageFragment(node);
23
+ return node?.type !== NodeType.ROOT && !isPageOrFragment(node);
19
24
  },
20
25
  handler: ({ editorService }) => {
21
26
  const nodes = editorService.get('nodes');
22
- nodes && editorService.remove(nodes);
27
+ nodes && editorService.remove(nodes, { historySource });
23
28
  },
24
29
  });
25
30
 
@@ -33,7 +38,10 @@ export const useCopyMenu = (): MenuButton => ({
33
38
  },
34
39
  });
35
40
 
36
- export const usePasteMenu = (menu?: ShallowRef<InstanceType<typeof ContentMenu> | null>): MenuButton => ({
41
+ export const usePasteMenu = (
42
+ historySource?: HistoryOpSource,
43
+ menu?: ShallowRef<InstanceType<typeof ContentMenu> | null>,
44
+ ): MenuButton => ({
37
45
  type: 'button',
38
46
  text: '粘贴',
39
47
  icon: markRaw(DocumentCopy),
@@ -52,14 +60,14 @@ export const usePasteMenu = (menu?: ShallowRef<InstanceType<typeof ContentMenu>
52
60
  const initialTop =
53
61
  calcValueByFontsize(stage?.renderer?.getDocument(), (rect.top || 0) - (parentRect?.top || 0)) /
54
62
  uiService.get('zoom');
55
- editorService.paste({ left: initialLeft, top: initialTop });
63
+ editorService.paste({ left: initialLeft, top: initialTop }, undefined, { historySource });
56
64
  } else {
57
- editorService.paste();
65
+ editorService.paste(undefined, undefined, { historySource });
58
66
  }
59
67
  },
60
68
  });
61
69
 
62
- const moveTo = async (id: Id, { editorService }: Services) => {
70
+ const moveTo = async (id: Id, { editorService }: Services, historySource?: HistoryOpSource) => {
63
71
  const nodes = editorService.get('nodes') || [];
64
72
  const parent = editorService.getNodeById(id) as MContainer;
65
73
 
@@ -69,10 +77,11 @@ const moveTo = async (id: Id, { editorService }: Services) => {
69
77
  // 不要再走 remove + add 两步,否则会被切成两条历史(且语义也不正确)。
70
78
  await editorService.moveToContainer(cloneDeep(nodes), parent.id, {
71
79
  doNotSwitchPage: true,
80
+ historySource,
72
81
  });
73
82
  };
74
83
 
75
- export const useMoveToMenu = ({ editorService }: Services): MenuButton => {
84
+ export const useMoveToMenu = ({ editorService }: Services, historySource?: HistoryOpSource): MenuButton => {
76
85
  const root = computed(() => editorService.get('root'));
77
86
 
78
87
  return {
@@ -89,7 +98,7 @@ export const useMoveToMenu = ({ editorService }: Services): MenuButton => {
89
98
  text: `${page.name}(${page.id})`,
90
99
  type: 'button',
91
100
  handler: (services: Services) => {
92
- moveTo(page.id, services);
101
+ moveTo(page.id, services, historySource);
93
102
  },
94
103
  })),
95
104
  };
@@ -10,6 +10,7 @@ const dataSourceFormConfig: TabConfig = {
10
10
  items: [
11
11
  {
12
12
  title: '数据定义',
13
+ status: 'fields',
13
14
  items: [
14
15
  {
15
16
  name: 'fields',
@@ -20,6 +21,7 @@ const dataSourceFormConfig: TabConfig = {
20
21
  },
21
22
  {
22
23
  title: '方法定义',
24
+ status: 'methods',
23
25
  items: [
24
26
  {
25
27
  name: 'methods',
@@ -233,19 +235,37 @@ export const getCascaderOptionsFromFields = (
233
235
  return result;
234
236
  };
235
237
 
236
- export const getFieldType = (ds: DataSourceSchema | undefined, fieldNames: string[]) => {
237
- let fields = ds?.fields;
238
- let type = '';
239
-
240
- for (const fieldName of fieldNames) {
241
- if (!fields?.length) return '';
242
-
243
- const field = fields.find((f) => f.name === fieldName);
244
- if (!field) return '';
238
+ /**
239
+ * 按字段名路径下钻 DataSchema。
240
+ * @param skipNumberIndices 为 true 时跳过数字段(模板路径中的数组下标,如 arr[0].x)
241
+ */
242
+ export const resolveFieldByPath = (
243
+ fields: DataSchema[] | undefined,
244
+ fieldNames: string[],
245
+ options: { skipNumberIndices?: boolean } = {},
246
+ ): { ok: boolean; field?: DataSchema; fields: DataSchema[]; failedName?: string } => {
247
+ let currentFields = fields || [];
248
+ let field: DataSchema | undefined;
245
249
 
246
- type = field.type || '';
247
- fields = field.fields;
250
+ for (const name of fieldNames) {
251
+ if (options.skipNumberIndices && isNumber(name)) {
252
+ continue;
253
+ }
254
+ if (!currentFields.length) {
255
+ return { ok: false, fields: currentFields, failedName: name };
256
+ }
257
+ field = currentFields.find((item) => item.name === name);
258
+ if (!field) {
259
+ return { ok: false, fields: currentFields, failedName: name };
260
+ }
261
+ currentFields = field.fields || [];
248
262
  }
249
263
 
250
- return type;
264
+ return { field, ok: true, fields: currentFields };
265
+ };
266
+
267
+ export const getFieldType = (ds: DataSourceSchema | undefined, fieldNames: string[]) => {
268
+ const { ok, field } = resolveFieldByPath(ds?.fields, fieldNames);
269
+ if (!ok) return '';
270
+ return field?.type || '';
251
271
  };
@@ -0,0 +1,149 @@
1
+ import serialize from 'serialize-javascript';
2
+
3
+ import type { Id, MApp } from '@tmagic/core';
4
+
5
+ import { error } from '../logger';
6
+
7
+ import type { CollectWorkerPayload, CollectWorkerRequest, CollectWorkerResponse, DepsData } from './worker';
8
+ import CollectWorker from './worker.ts?worker&inline';
9
+
10
+ export interface CollectWorkerResult {
11
+ deps: DepsData;
12
+ nodeIds: Id[];
13
+ }
14
+
15
+ /**
16
+ * 依赖收集 worker 的主线程客户端
17
+ *
18
+ * 依赖收集需要深度遍历整棵节点树并对每个属性做匹配,节点/数据源多时会长时间占用主线程导致页面卡死,
19
+ * 这里把遍历匹配放到 worker 中执行,主线程只负责把结果写回 target。
20
+ *
21
+ * 全量收集与增量收集共用一个常驻 worker:增量收集调用频繁(每次节点更新都会触发),
22
+ * 按次创建 worker 的启动开销无法接受,也容易漏掉销毁导致线程泄漏。
23
+ */
24
+ export class CollectWorkerClient {
25
+ private worker: Worker | null = null;
26
+
27
+ private seed = 0;
28
+
29
+ private pending = new Map<number, (response: CollectWorkerResponse | null) => void>();
30
+
31
+ public get isSupported() {
32
+ return typeof Worker !== 'undefined';
33
+ }
34
+
35
+ /**
36
+ * 在 worker 中全量收集整个 DSL 的依赖,target 由 worker 根据 DSL 重建
37
+ * @returns 收集结果,返回 null 表示 worker 不可用或执行失败
38
+ */
39
+ public collectDsl(dsl: MApp): Promise<DepsData | null> {
40
+ return this.request((id) => ({ id, dsl: serialize(dsl) })).then((response) => response?.deps || null);
41
+ }
42
+
43
+ /**
44
+ * 在 worker 中增量收集指定节点的依赖,target 以可序列化描述的形式传入
45
+ * @returns 收集结果,返回 null 表示 worker 不可用或执行失败,调用方需要回退到主线程收集
46
+ */
47
+ public collect(payload: CollectWorkerPayload): Promise<CollectWorkerResult | null> {
48
+ return this.request((id) => ({ id, payload: serialize(payload) })).then((response) =>
49
+ response ? { deps: response.deps || {}, nodeIds: response.nodeIds || [] } : null,
50
+ );
51
+ }
52
+
53
+ public terminate() {
54
+ this.worker?.terminate();
55
+ this.worker = null;
56
+ this.settleAllPending();
57
+ }
58
+
59
+ /**
60
+ * 丢弃在途请求并重建 worker
61
+ * clearIdleTasks / reset 中断收集时调用,避免已 abort 的长任务继续占着常驻 worker 拖慢后续收集
62
+ */
63
+ public abort() {
64
+ this.terminate();
65
+ }
66
+
67
+ /**
68
+ * worker 按收到的顺序逐个处理请求,因此请求间不会互相打断,用 id 把结果分发回各自的调用方
69
+ */
70
+ private request(createRequest: (id: number) => CollectWorkerRequest): Promise<CollectWorkerResponse | null> {
71
+ const worker = this.getWorker();
72
+
73
+ if (!worker) {
74
+ return Promise.resolve(null);
75
+ }
76
+
77
+ this.seed += 1;
78
+ const id = this.seed;
79
+
80
+ return new Promise<CollectWorkerResponse | null>((resolve) => {
81
+ this.pending.set(id, resolve);
82
+
83
+ try {
84
+ // 节点配置中可能存在函数等无法结构化克隆的值,需要先序列化再传递
85
+ worker.postMessage(createRequest(id));
86
+ } catch (e) {
87
+ error('magic editor: 依赖收集 worker 通信失败', e);
88
+ this.pending.delete(id);
89
+ resolve(null);
90
+ }
91
+ });
92
+ }
93
+
94
+ private getWorker() {
95
+ if (!this.isSupported) {
96
+ return null;
97
+ }
98
+
99
+ if (this.worker) {
100
+ return this.worker;
101
+ }
102
+
103
+ try {
104
+ const worker: Worker = new CollectWorker();
105
+ worker.onmessage = (e: MessageEvent<CollectWorkerResponse>) => {
106
+ this.handleResponse(e.data);
107
+ };
108
+ // worker 整体异常时无法定位到具体请求,只能结算全部在途请求并重建 worker
109
+ worker.onerror = () => {
110
+ this.handleFatalError();
111
+ };
112
+ worker.onmessageerror = () => {
113
+ this.handleFatalError();
114
+ };
115
+ this.worker = worker;
116
+ } catch (e) {
117
+ error('magic editor: 依赖收集 worker 创建失败', e);
118
+ return null;
119
+ }
120
+
121
+ return this.worker;
122
+ }
123
+
124
+ private handleResponse(response: CollectWorkerResponse) {
125
+ const resolve = this.pending.get(response?.id);
126
+
127
+ if (!resolve) {
128
+ return;
129
+ }
130
+
131
+ this.pending.delete(response.id);
132
+ resolve(response.failed ? null : response);
133
+ }
134
+
135
+ private handleFatalError() {
136
+ this.worker?.terminate();
137
+ this.worker = null;
138
+ this.settleAllPending();
139
+ }
140
+
141
+ private settleAllPending() {
142
+ const resolvers = [...this.pending.values()];
143
+ this.pending.clear();
144
+
145
+ for (const resolve of resolvers) {
146
+ resolve(null);
147
+ }
148
+ }
149
+ }
@@ -1,5 +1,7 @@
1
1
  import { EventEmitter } from 'events';
2
2
 
3
+ import { error } from '../logger';
4
+
3
5
  export interface IdleTaskEvents {
4
6
  finish: [];
5
7
  'hight-level-finish': [];
@@ -11,6 +13,18 @@ type TaskList<T> = {
11
13
  data: T;
12
14
  }[];
13
15
 
16
+ /**
17
+ * 回调因 timeout 触发(主线程一直没有空闲)时,单次回调执行任务的时间预算,单位 ms
18
+ * 参考一帧内可让出的余量:既保证队列有进展,又不长时间阻塞主线程
19
+ */
20
+ const TIMEOUT_RUN_BUDGET = 5;
21
+
22
+ /**
23
+ * 回调因 timeout 触发时,每两次读取时钟之间执行的任务数
24
+ * 与空闲时间 <=5ms 时的批量保持一致,避免每个任务都读一次时钟
25
+ */
26
+ const TIMEOUT_BATCH_SIZE = 10;
27
+
14
28
  globalThis.requestIdleCallback =
15
29
  globalThis.requestIdleCallback ||
16
30
  function (cb) {
@@ -25,6 +39,12 @@ globalThis.requestIdleCallback =
25
39
  }, 1);
26
40
  };
27
41
 
42
+ globalThis.cancelIdleCallback =
43
+ globalThis.cancelIdleCallback ||
44
+ function (handle) {
45
+ clearTimeout(handle as unknown as ReturnType<typeof setTimeout>);
46
+ };
47
+
28
48
  export class IdleTask<T = any> extends EventEmitter {
29
49
  private taskList: TaskList<T> = [];
30
50
 
@@ -58,7 +78,7 @@ export class IdleTask<T = any> extends EventEmitter {
58
78
  this.taskHandle = null;
59
79
 
60
80
  this.emit('update-task-length', {
61
- length: this.taskList.length + this.hightLevelTaskList.length,
81
+ length: this.getTaskLength(),
62
82
  hightLevelLength: this.hightLevelTaskList.length,
63
83
  });
64
84
  }
@@ -82,51 +102,100 @@ export class IdleTask<T = any> extends EventEmitter {
82
102
  }
83
103
 
84
104
  private runTaskQueue(deadline: IdleDeadline) {
85
- const { hightLevelTaskList, taskList } = this;
86
-
87
- // 动画会占用空闲时间,当任务一直无法执行时,看看是否有动画正在播放
88
- // 根据空闲时间的多少来决定执行的任务数,保证页面不卡死的情况下尽量多执行任务,不然当任务数巨大时,执行时间会很久
89
- // 执行不完不会影响配置,但是会影响画布渲染
90
- while (deadline.timeRemaining() > 0 && (taskList.length || hightLevelTaskList.length)) {
91
- const timeRemaining = deadline.timeRemaining();
92
- let times = 0;
93
- if (timeRemaining <= 5) {
94
- times = 10;
95
- } else if (timeRemaining <= 10) {
96
- times = 100;
97
- } else if (timeRemaining <= 15) {
98
- times = 300;
99
- } else {
100
- times = 600;
105
+ // 本次回调已触发,句柄随之失效;置空后 clearTasks / enqueueTask 才能正确判断是否需要重新调度
106
+ this.taskHandle = null;
107
+
108
+ try {
109
+ // 主线程一直没有空闲时,回调只会因 timeout 触发,此时 deadline.timeRemaining() 恒为 0(规范行为)。
110
+ // 若仍以它作为循环条件,一个任务都执行不了,而 finishRun 又会接着重新调度,
111
+ // 队列就会无限空转下去:依赖收集永远不结束,collecting 卡在 true,画布也不再更新。
112
+ // 这种情况下改用自有时间预算推进,既保证有进展,又不会像放开循环那样长时间阻塞主线程。
113
+ if (deadline.didTimeout) {
114
+ const start = Date.now();
115
+ do {
116
+ this.runTaskBatch(TIMEOUT_BATCH_SIZE);
117
+ } while (this.getTaskLength() && Date.now() - start < TIMEOUT_RUN_BUDGET);
118
+
119
+ return;
101
120
  }
102
121
 
103
- for (let i = 0; i < times; i++) {
104
- const task = hightLevelTaskList.length > 0 ? hightLevelTaskList.shift() : taskList.shift();
105
- if (task) {
106
- task.handler(task.data);
122
+ // 动画会占用空闲时间,当任务一直无法执行时,看看是否有动画正在播放
123
+ // 根据空闲时间的多少来决定执行的任务数,保证页面不卡死的情况下尽量多执行任务,不然当任务数巨大时,执行时间会很久
124
+ // 执行不完不会影响配置,但是会影响画布渲染
125
+ while (deadline.timeRemaining() > 0 && this.getTaskLength()) {
126
+ const timeRemaining = deadline.timeRemaining();
127
+ let times = 0;
128
+ if (timeRemaining <= 5) {
129
+ times = 10;
130
+ } else if (timeRemaining <= 10) {
131
+ times = 100;
132
+ } else if (timeRemaining <= 15) {
133
+ times = 300;
134
+ } else {
135
+ times = 600;
107
136
  }
108
137
 
109
- if (hightLevelTaskList.length === 0 && taskList.length === 0) {
110
- break;
111
- }
138
+ this.runTaskBatch(times);
112
139
  }
140
+ } finally {
141
+ // 必须放在 finally 中:一旦这里被跳过,taskHandle 会一直是真值,
142
+ // enqueueTask 也就不会再重新调度,剩余任务与任务数将永久停在当前状态
143
+ this.finishRun();
113
144
  }
145
+ }
114
146
 
115
- if (!hightLevelTaskList.length) {
116
- this.emit('hight-level-finish');
147
+ /**
148
+ * 执行一批任务,队列被清空时提前结束
149
+ */
150
+ private runTaskBatch(times: number) {
151
+ for (let i = 0; i < times; i++) {
152
+ // 每次都从实例上取队列,任务执行过程中调用 clearTasks 能立即生效,不会继续消费已被清空的旧队列
153
+ const task = this.hightLevelTaskList.length > 0 ? this.hightLevelTaskList.shift() : this.taskList.shift();
154
+ if (task) {
155
+ this.runTask(task);
156
+ }
157
+
158
+ if (!this.getTaskLength()) {
159
+ break;
160
+ }
117
161
  }
162
+ }
163
+
164
+ /**
165
+ * 单个任务失败不能中断整个队列,否则后续任务永远不会被执行,
166
+ * 依赖收集会停在半路(收集中状态与剩余任务数都不再变化)
167
+ */
168
+ private runTask(task: TaskList<T>[number]) {
169
+ try {
170
+ task.handler(task.data);
171
+ } catch (e) {
172
+ error('magic editor: 空闲任务执行失败', e);
173
+ }
174
+ }
118
175
 
119
- if (hightLevelTaskList.length || taskList.length) {
120
- this.taskHandle = globalThis.requestIdleCallback(this.runTaskQueue.bind(this), { timeout: 300 });
121
- } else {
122
- this.taskHandle = 0;
176
+ private finishRun() {
177
+ try {
178
+ if (!this.hightLevelTaskList.length) {
179
+ this.emit('hight-level-finish');
180
+ }
181
+ } finally {
182
+ if (this.getTaskLength()) {
183
+ // 任务执行或事件监听中可能已经重新调度过
184
+ if (!this.taskHandle) {
185
+ this.taskHandle = globalThis.requestIdleCallback(this.runTaskQueue.bind(this), { timeout: 300 });
186
+ }
187
+ } else {
188
+ this.emit('finish');
189
+ }
123
190
 
124
- this.emit('finish');
191
+ this.emit('update-task-length', {
192
+ length: this.getTaskLength(),
193
+ hightLevelLength: this.hightLevelTaskList.length,
194
+ });
125
195
  }
196
+ }
126
197
 
127
- this.emit('update-task-length', {
128
- length: taskList.length + hightLevelTaskList.length,
129
- hightLevelLength: hightLevelTaskList.length,
130
- });
198
+ private getTaskLength() {
199
+ return this.taskList.length + this.hightLevelTaskList.length;
131
200
  }
132
201
  }
@@ -3,30 +3,85 @@ import {
3
3
  createDataSourceCondTarget,
4
4
  createDataSourceMethodTarget,
5
5
  createDataSourceTarget,
6
+ createTargetByDescriptor,
6
7
  type DepData,
8
+ type DepExtendedData,
7
9
  DepTargetType,
8
10
  type Id,
9
11
  type MApp,
12
+ type TargetDescriptor,
13
+ type TargetNode,
10
14
  traverseTarget,
11
15
  Watcher,
12
16
  } from '@tmagic/core';
13
17
 
14
18
  import { error } from '../logger';
15
19
 
16
- onmessage = (e) => {
17
- const watcher = new Watcher({ initialTargets: {} });
20
+ export type DepsData = Record<string, Record<Id, DepData>>;
18
21
 
19
- const { dsl } = e.data;
22
+ /** 全量收集请求:worker 中根据 DSL 重建代码块/数据源 target */
23
+ export interface DslCollectRequest {
24
+ /** 请求 id,用于把结果与调用方对应起来 */
25
+ id: number;
26
+ /** serialize-javascript 序列化后的 MApp */
27
+ dsl: string;
28
+ }
20
29
 
30
+ export interface CollectWorkerPayload {
31
+ /** 待收集的节点 */
32
+ nodes: TargetNode[];
33
+ /** 参与本次收集的 target 描述,worker 中据此重建 target */
34
+ targets: TargetDescriptor[];
35
+ depExtendedData: DepExtendedData;
36
+ deep: boolean;
37
+ }
38
+
39
+ /** 增量收集请求:target 由主线程以可序列化描述的形式传入 */
40
+ export interface NodesCollectRequest {
41
+ id: number;
42
+ /** serialize-javascript 序列化后的 CollectWorkerPayload */
43
+ payload: string;
44
+ }
45
+
46
+ export type CollectWorkerRequest = DslCollectRequest | NodesCollectRequest;
47
+
48
+ export interface CollectWorkerResponse {
49
+ id: number;
50
+ /** 收集结果,结构为 { [target.type]: { [target.id]: deps } } */
51
+ deps: DepsData;
52
+ /** 增量收集时本次覆盖到的节点 id(deep=true 时含子孙),主线程据此删除旧依赖 */
53
+ nodeIds?: Id[];
54
+ /** 收集失败,调用方需要回退到主线程收集 */
55
+ failed?: boolean;
56
+ }
57
+
58
+ /**
59
+ * 收集本次会覆盖到的节点 id
60
+ * 必须与 deep 一致:deep=false 时不能带上子孙 id,否则写回阶段 removeDep 会清掉未重收的子节点依赖
61
+ */
62
+ const getNodeIds = (nodes: TargetNode[], deep: boolean, ids: Id[] = []) => {
63
+ for (const node of nodes) {
64
+ ids.push(node.id);
65
+
66
+ if (deep && Array.isArray(node.items) && node.items.length) {
67
+ getNodeIds(node.items, deep, ids);
68
+ }
69
+ }
70
+
71
+ return ids;
72
+ };
73
+
74
+ const collectDsl = ({ id, dsl }: DslCollectRequest) => {
21
75
  try {
22
76
  // eslint-disable-next-line no-eval
23
77
  const mApp: MApp = eval(`(${dsl})`);
24
78
 
25
79
  if (!mApp) {
26
- postMessage({});
80
+ postMessage({ id, deps: {} });
81
+ return;
27
82
  }
28
83
 
29
- watcher.clearTargets();
84
+ const watcher = new Watcher({ initialTargets: {} });
30
85
 
31
86
  if (mApp.codeBlocks) {
32
87
  for (const [id, code] of Object.entries(mApp.codeBlocks)) {
@@ -48,7 +103,7 @@ onmessage = (e) => {
48
103
  watcher.collectItems(page, targets, { pageId: page.id }, true);
49
104
  }
50
105
 
51
- const data: Record<string, Record<Id, DepData>> = {
106
+ const deps: DepsData = {
52
107
  [DepTargetType.DATA_SOURCE]: {},
53
108
  [DepTargetType.DATA_SOURCE_METHOD]: {},
54
109
  [DepTargetType.DATA_SOURCE_COND]: {},
@@ -56,12 +111,61 @@ onmessage = (e) => {
56
111
  };
57
112
 
58
113
  traverseTarget(watcher.getTargetsList(), (target) => {
59
- data[target.type][target.id] = target.deps;
114
+ deps[target.type][target.id] = target.deps;
60
115
  });
61
116
 
62
- postMessage(data);
117
+ const response: CollectWorkerResponse = { id, deps };
118
+ postMessage(response);
63
119
  } catch (e: any) {
64
120
  error(e);
65
- postMessage({});
121
+ const response: CollectWorkerResponse = { id, deps: {}, failed: true };
122
+ postMessage(response);
66
123
  }
67
124
  };
125
+
126
+ const collectNodes = ({ id, payload }: NodesCollectRequest) => {
127
+ try {
128
+ // eslint-disable-next-line no-eval
129
+ const { nodes, targets: descriptors, depExtendedData, deep }: CollectWorkerPayload = eval(`(${payload})`);
130
+
131
+ const watcher = new Watcher({ initialTargets: {} });
132
+ // worker 中 target 均为新建(deps 为空),无需删除阶段,直接批量收集
133
+ const targets = descriptors.map((descriptor) => createTargetByDescriptor(descriptor));
134
+
135
+ for (const node of nodes) {
136
+ watcher.collectItems(node, targets, depExtendedData, deep);
137
+ }
138
+
139
+ const deps: DepsData = {};
140
+ for (const target of targets) {
141
+ if (!deps[target.type]) {
142
+ deps[target.type] = {};
143
+ }
144
+ deps[target.type][target.id] = target.deps;
145
+ }
146
+
147
+ const response: CollectWorkerResponse = { id, deps, nodeIds: getNodeIds(nodes, deep) };
148
+ postMessage(response);
149
+ } catch (e: any) {
150
+ error(e);
151
+ const response: CollectWorkerResponse = { id, deps: {}, nodeIds: [], failed: true };
152
+ postMessage(response);
153
+ }
154
+ };
155
+
156
+ /**
157
+ * 依赖收集 worker
158
+ *
159
+ * 依赖收集需要深度遍历整棵节点树并对每个属性做 target 匹配,节点/数据源多时会长时间占用主线程导致页面卡死,
160
+ * 因此把遍历匹配放到 worker 中执行。
161
+ * 全量与增量收集共用一个常驻 worker:收集逻辑只打进一份 inline worker 产物,
162
+ * 也不会因为频繁收集而反复创建线程,每个请求用 id 与调用方对应。
163
+ */
164
+ onmessage = (e: MessageEvent<CollectWorkerRequest>) => {
165
+ if ('dsl' in e.data) {
166
+ collectDsl(e.data);
167
+ return;
168
+ }
169
+
170
+ collectNodes(e.data);
171
+ };