@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
@@ -1,322 +1,196 @@
1
+ import { getEditorConfig } from "../utils/config.js";
1
2
  import BaseService from "./BaseService.js";
2
3
  import { UndoRedo } from "../utils/undo-redo.js";
4
+ import { deserializeStacks, getOrCreateStack, markStackSaved, mergeSteps, serializeStacks, undoFloor } from "../utils/history.js";
5
+ import { idbGet, idbSet } from "../utils/indexed-db.js";
6
+ import editor_default from "./editor.js";
7
+ import { guid } from "@tmagic/utils";
3
8
  import { reactive } from "vue";
4
- import { cloneDeep } from "lodash-es";
5
- var history_default = new class History extends BaseService {
6
- /**
7
- * 把单个代码块栈拆成若干 group:
8
- * - 把"新增/删除"独立成组(语义上属于一次性事件,不应与 update 合并);
9
- * - 连续 'update' 合并到同一组,组内 steps 顺序就是发生顺序。
10
- */
11
- static mergeCodeBlockSteps(codeBlockId, list, cursor) {
12
- const groups = [];
13
- let current = null;
14
- const currentIndex = cursor - 1;
15
- list.forEach((step, index) => {
16
- const opType = History.detectOpType(step.oldContent, step.newContent);
17
- const applied = index < cursor;
18
- const isCurrent = index === currentIndex;
19
- if (opType === "update" && current?.opType === "update") {
20
- current.steps.push({
21
- step,
22
- index,
23
- applied,
24
- isCurrent
25
- });
26
- current.applied = applied;
27
- if (isCurrent) current.isCurrent = true;
28
- } else {
29
- current = {
30
- kind: "code-block",
31
- id: codeBlockId,
32
- opType,
33
- steps: [{
34
- step,
35
- index,
36
- applied,
37
- isCurrent
38
- }],
39
- applied,
40
- isCurrent
41
- };
42
- groups.push(current);
43
- }
44
- });
45
- return groups;
46
- }
47
- static mergeDataSourceSteps(dataSourceId, list, cursor) {
48
- const groups = [];
49
- let current = null;
50
- const currentIndex = cursor - 1;
51
- list.forEach((step, index) => {
52
- const opType = History.detectOpType(step.oldSchema, step.newSchema);
53
- const applied = index < cursor;
54
- const isCurrent = index === currentIndex;
55
- if (opType === "update" && current?.opType === "update") {
56
- current.steps.push({
57
- step,
58
- index,
59
- applied,
60
- isCurrent
61
- });
62
- current.applied = applied;
63
- if (isCurrent) current.isCurrent = true;
64
- } else {
65
- current = {
66
- kind: "data-source",
67
- id: dataSourceId,
68
- opType,
69
- steps: [{
70
- step,
71
- index,
72
- applied,
73
- isCurrent
74
- }],
75
- applied,
76
- isCurrent
77
- };
78
- groups.push(current);
79
- }
80
- });
81
- return groups;
9
+ //#region packages/editor/src/services/history.ts
10
+ var canUsePluginMethods = { sync: [
11
+ "push",
12
+ "undo",
13
+ "redo"
14
+ ] };
15
+ /** 各内置历史类型的默认展示名称(用于历史面板 tab / 分组标题等)。扩展类型可通过 registerStepType / setStepName 登记。 */
16
+ var DEFAULT_STEP_NAMES = {
17
+ page: "页面",
18
+ codeBlock: "代码块",
19
+ dataSource: "数据源"
20
+ };
21
+ /** 各历史类型对应的分组 `kind`(展示用):page→page,codeBlock→code-block,dataSource→data-source。扩展类型缺省回退到 stepType 本身。 */
22
+ var STEP_TYPE_KIND = {
23
+ page: "page",
24
+ codeBlock: "code-block",
25
+ dataSource: "data-source"
26
+ };
27
+ /** 历史记录持久化快照的默认存储位置与结构版本。 */
28
+ var DEFAULT_DB_NAME = "tmagic-editor";
29
+ var DEFAULT_STORE_NAME = "history";
30
+ var DEFAULT_KEY = "default";
31
+ var PERSIST_VERSION = 3;
32
+ var History = class extends BaseService {
33
+ state = reactive({
34
+ steps: {
35
+ page: {},
36
+ codeBlock: {},
37
+ dataSource: {}
38
+ },
39
+ stepNames: { ...DEFAULT_STEP_NAMES }
40
+ });
41
+ constructor() {
42
+ super([...canUsePluginMethods.sync.map((methodName) => ({
43
+ name: methodName,
44
+ isAsync: false
45
+ }))]);
82
46
  }
83
47
  /**
84
- * 根据 old/new 是否为 null 推断 opType(与 push 时的约定一致)。
48
+ * 注册一个扩展历史类型,使其可与内置 `page` / `codeBlock` / `dataSource` 一样走统一的
49
+ * {@link push} / {@link undo} / {@link redo}(按 id 分栈、独立 undo/redo)。
50
+ *
51
+ * @param stepType 自定义历史类型标识(勿与内置类型重名)
52
+ * @param options.event push/undo/redo 后派发的事件名,缺省为 `${stepType}-history-change`
53
+ * @param options.name 历史面板中的展示名称(tab / 分组标题等),缺省回退到 stepType 本身
85
54
  */
86
- static detectOpType(oldVal, newVal) {
87
- if (oldVal === null && newVal !== null) return "add";
88
- if (oldVal !== null && newVal === null) return "remove";
89
- return "update";
55
+ registerStepType(stepType, options = {}) {
56
+ this.getStepBucket(stepType);
57
+ if (options.name !== void 0) this.state.stepNames[stepType] = options.name;
90
58
  }
91
59
  /**
92
- * 把页面栈拆成若干 group:
93
- * - 单节点的 'update' 按 targetId 与相邻同 targetId 的 update 合并到一个 group;
94
- * - 'add' / 'remove' 始终独立成组(语义上是结构变更,不应被收纳进单节点修改组);
95
- * - 多节点 'update'(如批量改属性)也独立成组(无明确单一目标,避免误合并)。
60
+ * 读取指定历史类型的展示名称(用于历史面板 tab / 分组标题等)。
61
+ * 未登记名称时回退到 stepType 本身。
96
62
  */
97
- static mergePageSteps(pageId, list, cursor) {
98
- const groups = [];
99
- let current = null;
100
- const currentIndex = cursor - 1;
101
- list.forEach((step, index) => {
102
- const applied = index < cursor;
103
- const isCurrent = index === currentIndex;
104
- const targetId = History.detectPageTargetId(step);
105
- const targetName = History.detectPageTargetName(step);
106
- const entry = {
107
- step,
108
- index,
109
- applied,
110
- isCurrent
111
- };
112
- const mergeable = step.opType === "update" && targetId !== void 0;
113
- if (mergeable && current?.opType === "update" && current.targetId === targetId) {
114
- current.steps.push(entry);
115
- current.applied = applied;
116
- if (isCurrent) current.isCurrent = true;
117
- if (targetName) current.targetName = targetName;
118
- } else {
119
- current = {
120
- kind: "page",
121
- pageId,
122
- opType: step.opType,
123
- targetId: mergeable ? targetId : void 0,
124
- targetName,
125
- steps: [entry],
126
- applied,
127
- isCurrent
128
- };
129
- groups.push(current);
130
- }
131
- });
132
- return groups;
63
+ getStepName(stepType) {
64
+ return this.state.stepNames[stepType] ?? `${stepType}`;
133
65
  }
134
66
  /**
135
- * 解析 StepValue 中的"目标节点 id"用于合并:
136
- * - 单节点 update:取唯一一项 updatedItems 的节点 id;
137
- * - 其它情形(多节点 update / add / remove):返回 undefined,表示不参与合并。
67
+ * 设置指定历史类型的展示名称(用于历史面板 tab / 分组标题等)。
68
+ * 内置 `page` / `codeBlock` / `dataSource` 也可在此覆盖默认中文名。
138
69
  */
139
- static detectPageTargetId(step) {
140
- if (step.opType !== "update") return void 0;
141
- const items = step.updatedItems;
142
- if (items?.length !== 1) return void 0;
143
- return items[0].newNode?.id ?? items[0].oldNode?.id;
144
- }
145
- /** 解析 StepValue 中的目标节点可读名(用于 UI 展示)。 */
146
- static detectPageTargetName(step) {
147
- if (step.opType === "update") {
148
- const items = step.updatedItems;
149
- if (items?.length === 1) {
150
- const node = items[0].newNode || items[0].oldNode;
151
- return node?.name || node?.type || (node?.id !== void 0 ? `${node.id}` : void 0);
152
- }
153
- return items?.length ? `${items.length} 个节点` : void 0;
154
- }
155
- if (step.opType === "add") {
156
- if (step.nodes?.length === 1) {
157
- const n = step.nodes[0];
158
- return n.name || n.type || `${n.id}`;
159
- }
160
- return step.nodes?.length ? `${step.nodes.length} 个节点` : void 0;
161
- }
162
- if (step.opType === "remove") {
163
- if (step.removedItems?.length === 1) {
164
- const n = step.removedItems[0].node;
165
- return n.name || n.type || `${n.id}`;
166
- }
167
- return step.removedItems?.length ? `${step.removedItems.length} 个节点` : void 0;
168
- }
169
- }
170
- state = reactive({
171
- pageSteps: {},
172
- pageId: void 0,
173
- canRedo: false,
174
- canUndo: false,
175
- codeBlockState: {},
176
- dataSourceState: {}
177
- });
178
- constructor() {
179
- super([]);
180
- this.on("change", this.setCanUndoRedo);
70
+ setStepName(stepType, name) {
71
+ this.state.stepNames[stepType] = name;
181
72
  }
182
73
  reset() {
183
- this.state.pageSteps = {};
184
- this.state.codeBlockState = {};
185
- this.state.dataSourceState = {};
186
- this.resetPage();
187
- }
188
- resetPage() {
189
- this.state.pageId = void 0;
190
- this.state.canRedo = false;
191
- this.state.canUndo = false;
192
- }
193
- changePage(page) {
194
- if (!page) return;
195
- this.state.pageId = page.id;
196
- if (!this.state.pageSteps[this.state.pageId]) this.state.pageSteps[this.state.pageId] = new UndoRedo();
197
- this.setCanUndoRedo();
198
- this.emit("page-change", this.state.pageSteps[this.state.pageId]);
74
+ this.clearAllSteps();
199
75
  }
200
76
  resetState() {
201
- this.state.pageId = void 0;
202
- this.state.pageSteps = {};
203
- this.state.canRedo = false;
204
- this.state.canUndo = false;
205
- this.state.codeBlockState = {};
206
- this.state.dataSourceState = {};
77
+ this.clearAllSteps();
207
78
  }
208
79
  /**
209
- * 把一条步骤推入指定页面的栈;不指定 pageId 时落到当前活动页。
80
+ * 为指定历史栈(默认 `page`,也适用于 codeBlock / dataSource / 扩展类型)种入一条「初始基线」记录。
210
81
  *
211
- * 跨页操作(例如 `moveToContainer` 把节点搬到其它页)必须显式传入 `pageId`,
212
- * 否则会把记录错误地落到操作发起页 / 当前激活页,破坏目标页 / 源页的撤销栈语义。
213
- */
214
- push(state, pageId) {
215
- const undoRedo = this.getUndoRedo(pageId);
216
- if (!undoRedo) return null;
217
- undoRedo.pushElement(state);
218
- if (pageId === void 0 || `${pageId}` === `${this.state.pageId}`) this.emit("change", state);
219
- return state;
220
- }
221
- /**
222
- * 推入一条代码块变更记录(与页面/节点完全无关),按 `codeBlockId` 维度独立一份 UndoRedo 栈。
82
+ * 该记录是一条 `opType: 'initial'` step,作为对应栈 **index 0 的固定底线**:
83
+ * - 它是一条真实入栈的 step(随栈一起持久化),但被钉为撤销/回滚的下限——cursor 永不低于它,
84
+ * 因此不会被 undo / goto / revert 触达(详见 {@link undo} / {@link undoFloor});
85
+ * - 历史面板把它过滤出分组列表(见 {@link getHistoryGroups}),改由底部「初始」行展示。
86
+ *
87
+ * 仅当目标栈为空时种入(保证 initial 一定位于 index 0);已存在 initial 底线时不重复种入。
223
88
  *
224
- * - 新增:oldContent = null,newContent = 新内容
225
- * - 更新:oldContent / newContent 都为对应内容
226
- * - 删除:newContent = null,oldContent = 删除前内容
227
- * - `changeRecords` 来自 form 端,撤销/重做时若有则按 propPath 局部覆盖;缺省才退化为整内容替换。
228
- * - 不直接驱动 codeBlockService,调用方负责实际写回。
89
+ * @param stepType 历史类型
90
+ * @param id 目标栈 id(page pageId,其余类型为对应资源 id)
91
+ * @param options 基线展示信息(名称 / 描述 / 来源)
229
92
  */
230
- pushCodeBlock(codeBlockId, payload) {
231
- if (!codeBlockId) return null;
232
- const step = {
233
- id: codeBlockId,
234
- oldContent: payload.oldContent ? cloneDeep(payload.oldContent) : null,
235
- newContent: payload.newContent ? cloneDeep(payload.newContent) : null,
236
- changeRecords: payload.changeRecords?.length ? cloneDeep(payload.changeRecords) : void 0,
237
- historyDescription: payload.historyDescription
93
+ setMarker(stepType, id, options = {}) {
94
+ if (!this.isValidStackId(id)) return null;
95
+ const existing = this.getMarker(stepType, id);
96
+ if (existing) return existing;
97
+ const stack = getOrCreateStack(this.getStepBucket(stepType), id);
98
+ if (stack.getLength() > 0) return null;
99
+ const marker = {
100
+ uuid: guid(),
101
+ opType: "initial",
102
+ diff: [],
103
+ data: {
104
+ name: options.name || "",
105
+ id
106
+ },
107
+ extra: {
108
+ ...options.extra || {},
109
+ ...stepType === "page" ? {
110
+ selectedBefore: [],
111
+ selectedAfter: [],
112
+ modifiedNodeIds: /* @__PURE__ */ new Map()
113
+ } : {}
114
+ },
115
+ historyDescription: options.description || "未修改的初始状态",
116
+ timestamp: Date.now(),
117
+ ...options.source ? { source: options.source } : {}
238
118
  };
239
- this.getCodeBlockUndoRedo(codeBlockId).pushElement(step);
240
- this.emit("code-block-history-change", codeBlockId, step);
241
- return step;
119
+ stack.pushElement(marker);
120
+ this.emit("marker-change", {
121
+ id,
122
+ marker,
123
+ stepType
124
+ });
125
+ return marker;
242
126
  }
243
127
  /**
244
- * 推入一条数据源变更记录(与页面/节点完全无关),按 `dataSourceId` 维度独立一份 UndoRedo 栈。
245
- * 行为同 pushCodeBlock(新增 oldSchema=null;删除 newSchema=null)。
128
+ * 读取指定历史栈的初始基线 step(栈 index 0 且 `opType: 'initial'`);
129
+ * 不存在或 id 缺省时返回 undefined。
246
130
  */
247
- pushDataSource(dataSourceId, payload) {
248
- if (!dataSourceId) return null;
249
- const step = {
250
- id: dataSourceId,
251
- oldSchema: payload.oldSchema ? cloneDeep(payload.oldSchema) : null,
252
- newSchema: payload.newSchema ? cloneDeep(payload.newSchema) : null,
253
- changeRecords: payload.changeRecords?.length ? cloneDeep(payload.changeRecords) : void 0,
254
- historyDescription: payload.historyDescription
255
- };
256
- this.getDataSourceUndoRedo(dataSourceId).pushElement(step);
257
- this.emit("data-source-history-change", dataSourceId, step);
131
+ getMarker(stepType, id) {
132
+ if (!this.isValidStackId(id)) return void 0;
133
+ const first = this.state.steps[stepType]?.[id]?.getElementList()[0];
134
+ return first?.opType === "initial" ? first : void 0;
135
+ }
136
+ push(stepType, step, id) {
137
+ if (!this.isValidStackId(id)) return null;
138
+ this.fillStepMeta(step);
139
+ getOrCreateStack(this.getStepBucket(stepType), id).pushElement(step);
140
+ this.emit("change", step, stepType, id);
258
141
  return step;
259
142
  }
260
- /** 撤销指定代码块的最近一次变更。 */
261
- undoCodeBlock(codeBlockId) {
262
- const undoRedo = this.state.codeBlockState[codeBlockId];
143
+ undo(stepType, id) {
144
+ if (!this.isValidStackId(id)) return null;
145
+ const undoRedo = this.state.steps[stepType]?.[id];
263
146
  if (!undoRedo) return null;
147
+ if (undoRedo.getCursor() <= undoFloor(undoRedo)) return null;
264
148
  const step = undoRedo.undo();
265
- if (step) this.emit("code-block-history-change", codeBlockId, step);
149
+ if (step) this.emit("change", step, stepType, id);
266
150
  return step;
267
151
  }
268
- /** 重做指定代码块的下一次变更。 */
269
- redoCodeBlock(codeBlockId) {
270
- const undoRedo = this.state.codeBlockState[codeBlockId];
152
+ redo(stepType, id) {
153
+ if (!this.isValidStackId(id)) return null;
154
+ const undoRedo = this.state.steps[stepType]?.[id];
271
155
  if (!undoRedo) return null;
272
156
  const step = undoRedo.redo();
273
- if (step) this.emit("code-block-history-change", codeBlockId, step);
157
+ if (step) this.emit("change", step, stepType, id);
274
158
  return step;
275
159
  }
276
- /** 是否可对指定代码块撤销。 */
277
- canUndoCodeBlock(codeBlockId) {
278
- return this.state.codeBlockState[codeBlockId]?.canUndo() ?? false;
279
- }
280
- /** 是否可对指定代码块重做。 */
281
- canRedoCodeBlock(codeBlockId) {
282
- return this.state.codeBlockState[codeBlockId]?.canRedo() ?? false;
283
- }
284
- /** 撤销指定数据源的最近一次变更。 */
285
- undoDataSource(dataSourceId) {
286
- const undoRedo = this.state.dataSourceState[dataSourceId];
287
- if (!undoRedo) return null;
288
- const step = undoRedo.undo();
289
- if (step) this.emit("data-source-history-change", dataSourceId, step);
290
- return step;
291
- }
292
- /** 重做指定数据源的下一次变更。 */
293
- redoDataSource(dataSourceId) {
294
- const undoRedo = this.state.dataSourceState[dataSourceId];
295
- if (!undoRedo) return null;
296
- const step = undoRedo.redo();
297
- if (step) this.emit("data-source-history-change", dataSourceId, step);
298
- return step;
299
- }
300
- /** 是否可对指定数据源撤销。 */
301
- canUndoDataSource(dataSourceId) {
302
- return this.state.dataSourceState[dataSourceId]?.canUndo() ?? false;
160
+ /**
161
+ * 是否可对指定历史栈撤销(cursor 高于 initial 基线底线)。
162
+ * @param stepType 历史类型
163
+ * @param id 目标栈 id;缺省 / 无效时返回 false
164
+ */
165
+ canUndo(stepType, id) {
166
+ if (!this.isValidStackId(id)) return false;
167
+ const undoRedo = this.state.steps[stepType]?.[id];
168
+ return undoRedo ? undoRedo.getCursor() > undoFloor(undoRedo) : false;
303
169
  }
304
- /** 是否可对指定数据源重做。 */
305
- canRedoDataSource(dataSourceId) {
306
- return this.state.dataSourceState[dataSourceId]?.canRedo() ?? false;
170
+ /**
171
+ * 是否可对指定历史栈重做。
172
+ * @param stepType 历史类型
173
+ * @param id 目标栈 id;缺省 / 无效时返回 false
174
+ */
175
+ canRedo(stepType, id) {
176
+ if (!this.isValidStackId(id)) return false;
177
+ return this.state.steps[stepType]?.[id]?.canRedo() ?? false;
307
178
  }
308
- undo() {
309
- const undoRedo = this.getUndoRedo();
310
- if (!undoRedo) return null;
311
- const state = undoRedo.undo();
312
- this.emit("change", state);
313
- return state;
179
+ /** 读取指定页面历史栈当前游标所在的 step(cursor - 1);无则返回 null。 */
180
+ getCurrentPageStep(pageId) {
181
+ if (!this.isValidStackId(pageId)) return null;
182
+ return this.state.steps.page[pageId]?.getCurrentElement() ?? null;
314
183
  }
315
- redo() {
316
- const undoRedo = this.getUndoRedo();
317
- if (!undoRedo) return null;
318
- const state = undoRedo.redo();
319
- this.emit("change", state);
184
+ /**
185
+ * `state` 替换指定页面栈当前游标所在的 step(并丢弃其后的重做尾部),游标不变。
186
+ * 用于「连续 set root 记录合并」等就地替换最新一条的场景;替换成功后派发 `change`。
187
+ */
188
+ replaceCurrentStep(stepType, state, id) {
189
+ if (!this.isValidStackId(id)) return null;
190
+ const undoRedo = getOrCreateStack(this.getStepBucket(stepType), id);
191
+ this.fillStepMeta(state);
192
+ if (!undoRedo.replaceCurrentElement(state)) return null;
193
+ this.emit("change", state, stepType, id);
320
194
  return state;
321
195
  }
322
196
  destroy() {
@@ -325,93 +199,121 @@ var history_default = new class History extends BaseService {
325
199
  this.removeAllPlugins();
326
200
  }
327
201
  /**
328
- * 取出当前活动页的历史步骤平铺列表(包含已应用 + 已撤销)。
329
- * 列表按时间正序,最早一步在最前面。
330
- * 通常 UI 应使用 `getPageHistoryGroups` 取已合并分组的版本;本方法仅为兼容/调试保留。
331
- */
332
- getPageStepList(pageId) {
333
- const targetPageId = pageId ?? this.state.pageId;
334
- if (!targetPageId) return [];
335
- const undoRedo = this.state.pageSteps[targetPageId];
336
- if (!undoRedo) return [];
337
- const list = undoRedo.getElementList();
338
- const cursor = undoRedo.getCursor();
339
- return list.map((step, index) => ({
340
- step,
341
- index,
342
- applied: index < cursor
343
- }));
344
- }
345
- /**
346
- * 取出当前活动页的历史栈,按"目标节点"做相邻合并:
347
- * - 连续修改同一节点(单节点 update)的多步合并为一个 group,组内可展开查看每步;
348
- * - add / remove / 多节点 update 始终独立成组。
349
- * 用于历史面板的"页面"tab 展示。
202
+ * 清空历史记录栈。统一入口,所有类型(page / codeBlock / dataSource / 扩展)行为一致:
203
+ * - 传入 `id`:仅清空 `stepType` 下该 id 对应的栈;
204
+ * - 缺省 `id`:清空 `stepType` 下的全部栈。
205
+ *
206
+ * 仅删除撤销/重做记录,不会改动 DSL / 代码块 / 数据源本身。清空时会**保留各栈原有的
207
+ * initial 基线**(文案 / 来源),无基线时清空成空栈。清空后派发 `clear`(签名 `(id, stepType)`)。
208
+ *
209
+ * @param stepType 历史类型
210
+ * @param id 目标栈 id;缺省表示清空该类型下全部栈
350
211
  */
351
- getPageHistoryGroups(pageId) {
352
- const targetPageId = pageId ?? this.state.pageId;
353
- if (!targetPageId) return [];
354
- const undoRedo = this.state.pageSteps[targetPageId];
355
- if (!undoRedo) return [];
356
- const list = undoRedo.getElementList();
357
- if (!list.length) return [];
358
- const cursor = undoRedo.getCursor();
359
- return History.mergePageSteps(targetPageId, list, cursor);
212
+ clear(stepType, id) {
213
+ const bucket = this.state.steps[stepType];
214
+ if (!bucket) return;
215
+ if (this.isValidStackId(id)) this.clearStack(stepType, id);
216
+ else if (id === void 0) Object.keys(bucket).forEach((stackId) => this.clearStack(stepType, stackId));
217
+ else return;
218
+ this.emit("clear", {
219
+ id,
220
+ stepType
221
+ });
360
222
  }
361
223
  /**
362
- * 取出全部代码块的历史栈,按 codeBlockId 分组。
363
- * 同一栈内相邻、同 opType 且作用于同一 id 的多步会被合并为一个 group:
364
- * - 这正是"代码块/数据源各自按 id 分栈"的天然表现,再叠加"连续修改同目标的相邻步骤合并展示"。
365
- * - 合并后 group 暴露子步骤数组,UI 可展开查看每一步的 changeRecords。
366
- * - applied 字段:组内最后一步是否处于已应用段。
224
+ * 标记历史记录为「已保存」(把对应栈当前游标所在的记录标为 `saved`)。统一入口:
225
+ * - 缺省 `id`:标记**全部类型、全部栈**(整份 DSL 落库场景),派发 `mark-saved` 且 `kind: 'all'`;
226
+ * - 传入 `id`:仅标记 `stepType` 下该 id 对应的栈,派发 `mark-saved` 且 `kind` 为 `stepType`。
227
+ *
228
+ * 同一栈内任意时刻最多只有一条记录为 `saved`;从 IndexedDB 恢复时游标会被定位到最近一条已保存记录之后。
229
+ *
230
+ * @param stepType 历史类型
231
+ * @param id 目标栈 id;缺省表示标记全部类型 / 全部栈
367
232
  */
368
- getCodeBlockHistoryGroups() {
369
- const groups = [];
370
- Object.entries(this.state.codeBlockState).forEach(([id, undoRedo]) => {
371
- if (!undoRedo) return;
372
- const list = undoRedo.getElementList();
373
- if (!list.length) return;
374
- const cursor = undoRedo.getCursor();
375
- groups.push(...History.mergeCodeBlockSteps(id, list, cursor));
233
+ markSaved(stepType, id) {
234
+ if (id === void 0) {
235
+ Object.values(this.state.steps).forEach((bucket) => Object.values(bucket).forEach(markStackSaved));
236
+ this.emit("mark-saved", { kind: "all" });
237
+ return;
238
+ }
239
+ if (!this.isValidStackId(id)) return;
240
+ markStackSaved(this.state.steps[stepType]?.[id]);
241
+ this.emit("mark-saved", {
242
+ kind: stepType,
243
+ id
376
244
  });
377
- return groups;
378
245
  }
379
246
  /**
380
- * 读取指定页面历史栈的当前游标(已应用步骤数量)。不传则取当前活动页。
381
- * 没有对应栈时返回 0。
247
+ * 派发「页面 / 页面片结构变更」事件(`page-structure-change`)。
248
+ *
249
+ * 常规 `editorService.add` / `remove` 页面节点不会写入 `page` 历史栈(见 editor.add / remove 中
250
+ * 对 isPageOrFragment 的分支),因此不会产生任何 historyService 事件。该方法用于在这些
251
+ * 场景(以及 setRoot 整体替换 DSL 增删页面)下,向外统一通知页面结构的增删变化,供业务方感知。
252
+ *
253
+ * 一次操作涉及多个页面时,调用方应把本次增删的页面**合并为一个 change 一次性传入**,
254
+ * 使一次操作只派发一个事件;`add` / `remove` 分别为本次新增与删除的页面列表(其一可为空数组)。
255
+ *
256
+ * @param change 本次结构变更:{ add: 新增的页面列表, remove: 删除的页面列表 }
382
257
  */
383
- getPageCursor(pageId) {
384
- const targetPageId = pageId ?? this.state.pageId;
385
- if (!targetPageId) return 0;
386
- return this.state.pageSteps[targetPageId]?.getCursor() ?? 0;
387
- }
388
- /** 读取指定代码块历史栈的当前游标。 */
389
- getCodeBlockCursor(codeBlockId) {
390
- return this.state.codeBlockState[codeBlockId]?.getCursor() ?? 0;
391
- }
392
- /** 读取指定数据源历史栈的当前游标。 */
393
- getDataSourceCursor(dataSourceId) {
394
- return this.state.dataSourceState[dataSourceId]?.getCursor() ?? 0;
258
+ notifyPageStructureChange(change) {
259
+ if (!change.add.length && !change.remove.length) return;
260
+ this.emit("page-structure-change", change);
395
261
  }
396
262
  /**
397
- * 取出指定代码块历史栈的平铺步骤列表(含 applied 标记)。供 revert 等按 index 索引步骤使用。
263
+ * 把当前内存中的全部历史栈(页面 / 代码块 / 数据源 / 扩展类型)序列化后写入本地 IndexedDB。
264
+ *
265
+ * - 每个 UndoRedo 栈连同其游标、容量一并保存,恢复后可继续 undo/redo;
266
+ * - `key` 用于区分不同活动页 / 项目(同一 store 下可保存多份快照),缺省为 `default`;
267
+ * - 返回写入成功的快照对象,便于调用方记录 savedAt 等信息;
268
+ * - 不支持 IndexedDB 的环境(如 SSR)会 reject。
398
269
  */
399
- getCodeBlockStepList(codeBlockId) {
400
- const undoRedo = this.state.codeBlockState[codeBlockId];
401
- if (!undoRedo) return [];
402
- const list = undoRedo.getElementList();
403
- const cursor = undoRedo.getCursor();
404
- return list.map((step, index) => ({
405
- step,
406
- index,
407
- applied: index < cursor
408
- }));
270
+ async saveToIndexedDB(options = {}) {
271
+ const { dbName = DEFAULT_DB_NAME, storeName = DEFAULT_STORE_NAME, key = DEFAULT_KEY, appId } = options;
272
+ const steps = {
273
+ page: {},
274
+ codeBlock: {},
275
+ dataSource: {}
276
+ };
277
+ Object.entries(this.state.steps).forEach(([stepType, bucket]) => {
278
+ steps[stepType] = serializeStacks(bucket);
279
+ });
280
+ const snapshot = {
281
+ version: PERSIST_VERSION,
282
+ steps,
283
+ savedAt: Date.now()
284
+ };
285
+ await idbSet(this.resolveDbName(dbName, appId), storeName, key, snapshot);
286
+ this.emit("save-to-indexed-db", snapshot);
287
+ return snapshot;
409
288
  }
410
289
  /**
411
- * 取出指定数据源历史栈的平铺步骤列表(含 applied 标记)。供 revert 等按 index 索引步骤使用。
290
+ * 从本地 IndexedDB 读取此前保存的历史快照并重建全部撤销/重做栈。
291
+ *
292
+ * - 读取到的每个栈都会经 {@link UndoRedo.fromSerialized} 还原(含游标),随后可直接 undo/redo;
293
+ * - 会整体覆盖当前内存中的历史状态(活动页由 editorService 维护,不在此恢复);
294
+ * - 找不到对应记录时返回 null,且不改动当前状态;
295
+ * - 不支持 IndexedDB 的环境(如 SSR)会 reject。
412
296
  */
413
- getDataSourceStepList(dataSourceId) {
414
- const undoRedo = this.state.dataSourceState[dataSourceId];
297
+ async restoreFromIndexedDB(options = {}) {
298
+ const { dbName = DEFAULT_DB_NAME, storeName = DEFAULT_STORE_NAME, key = DEFAULT_KEY, appId } = options;
299
+ const snapshot = await idbGet(this.resolveDbName(dbName, appId), storeName, key);
300
+ if (!snapshot) return null;
301
+ const parseDSL = getEditorConfig("parseDSL");
302
+ const steps = {
303
+ page: {},
304
+ codeBlock: {},
305
+ dataSource: {}
306
+ };
307
+ Object.entries(snapshot.steps).forEach(([stepType, bucket]) => {
308
+ steps[stepType] = deserializeStacks(bucket, parseDSL);
309
+ });
310
+ this.state.steps = steps;
311
+ this.emit("restore-from-indexed-db", snapshot);
312
+ return snapshot;
313
+ }
314
+ getStepList(stepType, id) {
315
+ if (!this.isValidStackId(id)) return [];
316
+ const undoRedo = this.state.steps[stepType]?.[id];
415
317
  if (!undoRedo) return [];
416
318
  const list = undoRedo.getElementList();
417
319
  const cursor = undoRedo.getCursor();
@@ -421,51 +323,113 @@ var history_default = new class History extends BaseService {
421
323
  applied: index < cursor
422
324
  }));
423
325
  }
326
+ getHistoryGroups(stepType, id) {
327
+ const bucket = this.state.steps[stepType];
328
+ if (!bucket) return [];
329
+ const kind = STEP_TYPE_KIND[stepType] ?? stepType;
330
+ const collect = (stackId) => {
331
+ const undoRedo = bucket[stackId];
332
+ if (!undoRedo) return [];
333
+ const list = undoRedo.getElementList();
334
+ if (!list.length) return [];
335
+ return mergeSteps(kind, stackId, list, undoRedo.getCursor()).filter((group) => group.opType !== "initial");
336
+ };
337
+ if (this.isValidStackId(id)) return collect(id);
338
+ return Object.keys(bucket).flatMap((stackId) => collect(stackId));
339
+ }
424
340
  /**
425
- * 取出全部数据源的历史栈,按 dataSourceId 分组。同上。
341
+ * 读取指定历史栈的当前游标(已应用步骤数量)。统一入口,替代旧的
342
+ * `getPageCursor` / `getCodeBlockCursor` / `getDataSourceCursor`。
343
+ * - `id` 缺省或非法、或对应栈不存在时返回 0;
344
+ * - `stepType` 支持 `page` / `codeBlock` / `dataSource` / 扩展类型。
426
345
  */
427
- getDataSourceHistoryGroups() {
428
- const groups = [];
429
- Object.entries(this.state.dataSourceState).forEach(([id, undoRedo]) => {
430
- if (!undoRedo) return;
431
- const list = undoRedo.getElementList();
432
- if (!list.length) return;
433
- const cursor = undoRedo.getCursor();
434
- groups.push(...History.mergeDataSourceSteps(id, list, cursor));
435
- });
436
- return groups;
346
+ getCursor(stepType, id) {
347
+ if (!this.isValidStackId(id)) return 0;
348
+ return this.state.steps[stepType]?.[id]?.getCursor() ?? 0;
437
349
  }
438
350
  /**
439
- * 取出指定页面的栈;不传 pageId 时按当前活动页取。
351
+ * 按历史记录 uuid 在指定历史类型的栈中查找其所属 id 与索引,统一入口,替代旧的
352
+ * `getPageStepIndexByUuid` / `findCodeBlockStepLocationByUuid` / `findDataSourceStepLocationByUuid`。
353
+ *
354
+ * - 传入 `id`:仅在该 id 对应的单个栈中查找(如页面历史按活动页查看,传入 pageId);
355
+ * - 缺省 `id`:遍历该类型下全部栈查找(代码块 / 数据源等按全部资源分桶的场景)。
440
356
  *
441
- * 跨页 push 时如果目标页的栈尚不存在(用户从未进入过该页),会按需创建一条空栈,
442
- * 这样切到目标页时 Ctrl+Z 也能撤回该步骤。
357
+ * 找不到时返回 null。供「按 uuid 回滚」等需要把 uuid 映射回 (id, index) 的场景使用。
358
+ *
359
+ * @param stepType 历史类型
360
+ * @param uuid 目标历史记录的 uuid
361
+ * @param id 目标栈 id;缺省表示遍历该类型下全部栈
443
362
  */
444
- getUndoRedo(pageId) {
445
- const targetPageId = pageId ?? this.state.pageId;
446
- if (!targetPageId) return null;
447
- if (!this.state.pageSteps[targetPageId]) this.state.pageSteps[targetPageId] = new UndoRedo();
448
- return this.state.pageSteps[targetPageId];
363
+ findStepLocationByUuid(stepType, uuid, id) {
364
+ if (!uuid) return null;
365
+ const bucket = this.state.steps[stepType];
366
+ if (!bucket) return null;
367
+ if (this.isValidStackId(id)) {
368
+ const index = this.getStepList(stepType, id).findIndex((entry) => entry.step.uuid === uuid);
369
+ return index >= 0 ? {
370
+ id,
371
+ index
372
+ } : null;
373
+ }
374
+ for (const stackId of Object.keys(bucket)) {
375
+ const index = this.getStepList(stepType, stackId).findIndex((entry) => entry.step.uuid === uuid);
376
+ if (index >= 0) return {
377
+ id: stackId,
378
+ index
379
+ };
380
+ }
381
+ return null;
449
382
  }
450
- setCanUndoRedo() {
451
- const undoRedo = this.getUndoRedo();
452
- this.state.canRedo = undoRedo?.canRedo() || false;
453
- this.state.canUndo = undoRedo?.canUndo() || false;
383
+ usePlugin(options) {
384
+ super.usePlugin(options);
385
+ }
386
+ emit(eventName, ...args) {
387
+ return super.emit(eventName, ...args);
454
388
  }
455
389
  /**
456
- * id 获取(或创建)指定代码块的 UndoRedo 栈。
390
+ * 取出指定历史类型的栈桶(`Record<id, UndoRedo>`);不存在时按需创建空桶,
391
+ * 从而支持通过 {@link registerStepType} 或首次 push 动态扩展历史类型。
457
392
  */
458
- getCodeBlockUndoRedo(codeBlockId) {
459
- if (!this.state.codeBlockState[codeBlockId]) this.state.codeBlockState[codeBlockId] = new UndoRedo();
460
- return this.state.codeBlockState[codeBlockId];
393
+ getStepBucket(stepType) {
394
+ if (!this.state.steps[stepType]) this.state.steps[stepType] = {};
395
+ return this.state.steps[stepType];
396
+ }
397
+ /**
398
+ * 清空单个历史栈并按需重建其 initial 基线(保留原基线的文案 / 来源)。
399
+ */
400
+ clearStack(stepType, id) {
401
+ const marker = this.getMarker(stepType, id);
402
+ this.getStepBucket(stepType)[id] = new UndoRedo();
403
+ if (marker) this.setMarker(stepType, id, {
404
+ name: marker.data?.name,
405
+ description: marker.historyDescription,
406
+ source: marker.source
407
+ });
408
+ }
409
+ /** 入栈前补全 step 的 uuid / timestamp(调用方未指定时)。 */
410
+ fillStepMeta(step) {
411
+ if (step.uuid === void 0) step.uuid = guid();
412
+ if (step.timestamp === void 0) step.timestamp = Date.now();
413
+ }
414
+ /** 校验「按 id 分栈」类型(codeBlock / dataSource / 扩展)的 id 是否有效。 */
415
+ isValidStackId(id) {
416
+ return id !== void 0 && id !== null && `${id}` !== "";
417
+ }
418
+ /** 清空全部历史栈内容(保留已注册的类型键,使扩展类型在 reset 后仍可用)。 */
419
+ clearAllSteps() {
420
+ Object.keys(this.state.steps).forEach((stepType) => {
421
+ this.state.steps[stepType] = {};
422
+ });
461
423
  }
462
424
  /**
463
- * id 获取(或创建)指定数据源的 UndoRedo 栈。
425
+ * 把基础 dbName 与当前 DSL(root app)的 id 拼成最终库名,实现不同应用历史隔离。
426
+ * 取不到 app id(如尚未加载 DSL)时退回基础 dbName。
464
427
  */
465
- getDataSourceUndoRedo(dataSourceId) {
466
- if (!this.state.dataSourceState[dataSourceId]) this.state.dataSourceState[dataSourceId] = new UndoRedo();
467
- return this.state.dataSourceState[dataSourceId];
428
+ resolveDbName(dbName, appId) {
429
+ const resolvedAppId = appId ?? editor_default.get("root")?.id;
430
+ return resolvedAppId ? `${dbName}-${resolvedAppId}` : dbName;
468
431
  }
469
- }();
432
+ };
433
+ var history_default = new History();
470
434
  //#endregion
471
435
  export { history_default as default };