@eclipse-glsp/client 2.8.0-next.8 → 2.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (279) hide show
  1. package/README.md +1 -1
  2. package/css/grid.css +2 -1
  3. package/lib/base/action-dispatcher.js +1 -4
  4. package/lib/base/action-dispatcher.js.map +1 -1
  5. package/lib/base/auto-complete/auto-complete-widget.js +4 -8
  6. package/lib/base/auto-complete/auto-complete-widget.js.map +1 -1
  7. package/lib/base/auto-complete/base-autocomplete-palette.js +1 -2
  8. package/lib/base/auto-complete/base-autocomplete-palette.js.map +1 -1
  9. package/lib/base/editor-context-service.js +4 -7
  10. package/lib/base/editor-context-service.js.map +1 -1
  11. package/lib/base/feedback/css-feedback.js +1 -1
  12. package/lib/base/feedback/css-feedback.js.map +1 -1
  13. package/lib/base/feedback/feedback-action-dispatcher.js +4 -6
  14. package/lib/base/feedback/feedback-action-dispatcher.js.map +1 -1
  15. package/lib/base/feedback/feedback-command.js +1 -2
  16. package/lib/base/feedback/feedback-command.js.map +1 -1
  17. package/lib/base/feedback/feedback-emitter.js +1 -2
  18. package/lib/base/feedback/feedback-emitter.js.map +1 -1
  19. package/lib/base/feedback/set-model-command.js +1 -2
  20. package/lib/base/feedback/set-model-command.js.map +1 -1
  21. package/lib/base/feedback/update-model-command.js +1 -2
  22. package/lib/base/feedback/update-model-command.js.map +1 -1
  23. package/lib/base/model/diagram-loader.js +4 -6
  24. package/lib/base/model/diagram-loader.js.map +1 -1
  25. package/lib/base/model/glsp-model-source.d.ts +1 -1
  26. package/lib/base/model/glsp-model-source.d.ts.map +1 -1
  27. package/lib/base/model/glsp-model-source.js +3 -5
  28. package/lib/base/model/glsp-model-source.js.map +1 -1
  29. package/lib/base/model/model-registry.js +1 -2
  30. package/lib/base/model/model-registry.js.map +1 -1
  31. package/lib/base/selection-service.js +3 -3
  32. package/lib/base/selection-service.js.map +1 -1
  33. package/lib/base/shortcuts/available-shortcuts-extension.js +3 -2
  34. package/lib/base/shortcuts/available-shortcuts-extension.js.map +1 -1
  35. package/lib/base/shortcuts/available-shortcuts-tool.js +3 -2
  36. package/lib/base/shortcuts/available-shortcuts-tool.js.map +1 -1
  37. package/lib/base/tool-manager/tool-manager.js +1 -1
  38. package/lib/base/tool-manager/tool-manager.js.map +1 -1
  39. package/lib/base/ui-extension/ui-extension.js +4 -6
  40. package/lib/base/ui-extension/ui-extension.js.map +1 -1
  41. package/lib/features/accessibility/edge-autocomplete/edge-autocomplete-palette.js +12 -17
  42. package/lib/features/accessibility/edge-autocomplete/edge-autocomplete-palette.js.map +1 -1
  43. package/lib/features/accessibility/edge-autocomplete/edge-autocomplete-tool.js +3 -2
  44. package/lib/features/accessibility/edge-autocomplete/edge-autocomplete-tool.js.map +1 -1
  45. package/lib/features/accessibility/element-navigation/diagram-navigation-tool.js +11 -15
  46. package/lib/features/accessibility/element-navigation/diagram-navigation-tool.js.map +1 -1
  47. package/lib/features/accessibility/element-navigation/left-right-top-bottom-navigator.js +2 -3
  48. package/lib/features/accessibility/element-navigation/left-right-top-bottom-navigator.js.map +1 -1
  49. package/lib/features/accessibility/element-navigation/local-element-navigator.js +2 -3
  50. package/lib/features/accessibility/element-navigation/local-element-navigator.js.map +1 -1
  51. package/lib/features/accessibility/focus-tracker/focus-tracker-tool.js +5 -4
  52. package/lib/features/accessibility/focus-tracker/focus-tracker-tool.js.map +1 -1
  53. package/lib/features/accessibility/global-keylistener-tool.js +4 -3
  54. package/lib/features/accessibility/global-keylistener-tool.js.map +1 -1
  55. package/lib/features/accessibility/keyboard-grid/keyboard-grid-search-palette.js +3 -2
  56. package/lib/features/accessibility/keyboard-grid/keyboard-grid-search-palette.js.map +1 -1
  57. package/lib/features/accessibility/keyboard-tool-palette/keyboard-tool-palette.js +5 -7
  58. package/lib/features/accessibility/keyboard-tool-palette/keyboard-tool-palette.js.map +1 -1
  59. package/lib/features/accessibility/toast/toast-handler.js +2 -4
  60. package/lib/features/accessibility/toast/toast-handler.js.map +1 -1
  61. package/lib/features/accessibility/toast/toast-tool.js +3 -2
  62. package/lib/features/accessibility/toast/toast-tool.js.map +1 -1
  63. package/lib/features/accessibility/view-key-tools/deselect-key-tool.js +3 -2
  64. package/lib/features/accessibility/view-key-tools/deselect-key-tool.js.map +1 -1
  65. package/lib/features/accessibility/view-key-tools/grid-cell-zoom-key-tool.js +4 -3
  66. package/lib/features/accessibility/view-key-tools/grid-cell-zoom-key-tool.js.map +1 -1
  67. package/lib/features/bounds/freeform-layout.js +1 -1
  68. package/lib/features/bounds/freeform-layout.js.map +1 -1
  69. package/lib/features/bounds/glsp-hidden-bounds-updater.d.ts +31 -1
  70. package/lib/features/bounds/glsp-hidden-bounds-updater.d.ts.map +1 -1
  71. package/lib/features/bounds/glsp-hidden-bounds-updater.js +119 -58
  72. package/lib/features/bounds/glsp-hidden-bounds-updater.js.map +1 -1
  73. package/lib/features/bounds/hbox-layout.js +7 -10
  74. package/lib/features/bounds/hbox-layout.js.map +1 -1
  75. package/lib/features/bounds/layout-data.js +2 -4
  76. package/lib/features/bounds/layout-data.js.map +1 -1
  77. package/lib/features/bounds/local-bounds.js +3 -4
  78. package/lib/features/bounds/local-bounds.js.map +1 -1
  79. package/lib/features/bounds/set-bounds-feedback-command.js +2 -3
  80. package/lib/features/bounds/set-bounds-feedback-command.js.map +1 -1
  81. package/lib/features/bounds/vbox-layout.js +7 -10
  82. package/lib/features/bounds/vbox-layout.js.map +1 -1
  83. package/lib/features/change-bounds/model.js +1 -1
  84. package/lib/features/change-bounds/model.js.map +1 -1
  85. package/lib/features/change-bounds/move-element-handler.js +1 -2
  86. package/lib/features/change-bounds/move-element-handler.js.map +1 -1
  87. package/lib/features/change-bounds/movement-restrictor.js +1 -2
  88. package/lib/features/change-bounds/movement-restrictor.js.map +1 -1
  89. package/lib/features/change-bounds/point-position-updater.js +1 -1
  90. package/lib/features/change-bounds/point-position-updater.js.map +1 -1
  91. package/lib/features/change-bounds/resize/resize-default-tool.js +4 -3
  92. package/lib/features/change-bounds/resize/resize-default-tool.js.map +1 -1
  93. package/lib/features/change-bounds/resize/resize-handler.js +1 -2
  94. package/lib/features/change-bounds/resize/resize-handler.js.map +1 -1
  95. package/lib/features/change-bounds/resize/resize-tool.js +4 -3
  96. package/lib/features/change-bounds/resize/resize-tool.js.map +1 -1
  97. package/lib/features/change-bounds/tracker.js +1 -2
  98. package/lib/features/change-bounds/tracker.js.map +1 -1
  99. package/lib/features/command-palette/command-palette-tool.js +3 -2
  100. package/lib/features/command-palette/command-palette-tool.js.map +1 -1
  101. package/lib/features/command-palette/command-palette.js +2 -3
  102. package/lib/features/command-palette/command-palette.js.map +1 -1
  103. package/lib/features/context-menu/glsp-context-menu-mouse-listener.js +2 -3
  104. package/lib/features/context-menu/glsp-context-menu-mouse-listener.js.map +1 -1
  105. package/lib/features/copy-paste/copy-paste-handler.d.ts +1 -1
  106. package/lib/features/copy-paste/copy-paste-handler.d.ts.map +1 -1
  107. package/lib/features/copy-paste/copy-paste-handler.js +3 -5
  108. package/lib/features/copy-paste/copy-paste-handler.js.map +1 -1
  109. package/lib/features/copy-paste/copy-paste-standalone.js +6 -9
  110. package/lib/features/copy-paste/copy-paste-standalone.js.map +1 -1
  111. package/lib/features/debug/debug-bounds-decorator.js +9 -12
  112. package/lib/features/debug/debug-bounds-decorator.js.map +1 -1
  113. package/lib/features/debug/debug-model.js +1 -1
  114. package/lib/features/debug/debug-model.js.map +1 -1
  115. package/lib/features/decoration/decoration-placer.js +3 -2
  116. package/lib/features/decoration/decoration-placer.js.map +1 -1
  117. package/lib/features/element-template/add-template-element.d.ts +6 -1
  118. package/lib/features/element-template/add-template-element.d.ts.map +1 -1
  119. package/lib/features/element-template/add-template-element.js +17 -5
  120. package/lib/features/element-template/add-template-element.js.map +1 -1
  121. package/lib/features/element-template/mouse-tracking-element-position-listener.js +1 -1
  122. package/lib/features/element-template/mouse-tracking-element-position-listener.js.map +1 -1
  123. package/lib/features/element-template/remove-template-element.js +1 -1
  124. package/lib/features/element-template/remove-template-element.js.map +1 -1
  125. package/lib/features/export/default-png-diagram-exporter.js +4 -7
  126. package/lib/features/export/default-png-diagram-exporter.js.map +1 -1
  127. package/lib/features/export/diagram-export-postprocessor.js +1 -2
  128. package/lib/features/export/diagram-export-postprocessor.js.map +1 -1
  129. package/lib/features/export/glsp-svg-exporter.d.ts.map +1 -1
  130. package/lib/features/export/glsp-svg-exporter.js +5 -6
  131. package/lib/features/export/glsp-svg-exporter.js.map +1 -1
  132. package/lib/features/export/request-export-command.js +1 -1
  133. package/lib/features/export/request-export-command.js.map +1 -1
  134. package/lib/features/grid/grid-model.js +1 -1
  135. package/lib/features/grid/grid-model.js.map +1 -1
  136. package/lib/features/helper-lines/helper-line-feedback.js +7 -8
  137. package/lib/features/helper-lines/helper-line-feedback.js.map +1 -1
  138. package/lib/features/helper-lines/model.d.ts +1 -1
  139. package/lib/features/helper-lines/model.d.ts.map +1 -1
  140. package/lib/features/helper-lines/model.js +3 -4
  141. package/lib/features/helper-lines/model.js.map +1 -1
  142. package/lib/features/hints/type-hint-provider.js +3 -5
  143. package/lib/features/hints/type-hint-provider.js.map +1 -1
  144. package/lib/features/label-edit/edit-label-tool.js +3 -2
  145. package/lib/features/label-edit/edit-label-tool.js.map +1 -1
  146. package/lib/features/label-edit-ui/label-edit-ui.js +2 -3
  147. package/lib/features/label-edit-ui/label-edit-ui.js.map +1 -1
  148. package/lib/features/navigation/navigation-target-resolver.js +1 -1
  149. package/lib/features/navigation/navigation-target-resolver.js.map +1 -1
  150. package/lib/features/routing/sticky-manhattan-anchors.js +9 -6
  151. package/lib/features/routing/sticky-manhattan-anchors.js.map +1 -1
  152. package/lib/features/routing/sticky-manhattan-edge-router.js +10 -12
  153. package/lib/features/routing/sticky-manhattan-edge-router.js.map +1 -1
  154. package/lib/features/search-palette/search-palette.js +3 -2
  155. package/lib/features/search-palette/search-palette.js.map +1 -1
  156. package/lib/features/search-palette/suggestions/edge-element-suggestions.js +2 -3
  157. package/lib/features/search-palette/suggestions/edge-element-suggestions.js.map +1 -1
  158. package/lib/features/search-palette/suggestions/named-element-suggestions.js +8 -11
  159. package/lib/features/search-palette/suggestions/named-element-suggestions.js.map +1 -1
  160. package/lib/features/select/select-feedback-command.js +1 -1
  161. package/lib/features/select/select-feedback-command.js.map +1 -1
  162. package/lib/features/select/select-mouse-listener.js +1 -2
  163. package/lib/features/select/select-mouse-listener.js.map +1 -1
  164. package/lib/features/status/status-overlay.js +4 -4
  165. package/lib/features/status/status-overlay.js.map +1 -1
  166. package/lib/features/tool-palette/tool-palette.d.ts.map +1 -1
  167. package/lib/features/tool-palette/tool-palette.js +16 -23
  168. package/lib/features/tool-palette/tool-palette.js.map +1 -1
  169. package/lib/features/tools/change-bounds/change-bounds-manager.js +4 -6
  170. package/lib/features/tools/change-bounds/change-bounds-manager.js.map +1 -1
  171. package/lib/features/tools/change-bounds/change-bounds-tool-feedback.js +3 -4
  172. package/lib/features/tools/change-bounds/change-bounds-tool-feedback.js.map +1 -1
  173. package/lib/features/tools/change-bounds/change-bounds-tool-move-feedback.js +4 -8
  174. package/lib/features/tools/change-bounds/change-bounds-tool-move-feedback.js.map +1 -1
  175. package/lib/features/tools/change-bounds/change-bounds-tool.js +6 -6
  176. package/lib/features/tools/change-bounds/change-bounds-tool.js.map +1 -1
  177. package/lib/features/tools/change-bounds/change-bounds-tracker.js +7 -10
  178. package/lib/features/tools/change-bounds/change-bounds-tracker.js.map +1 -1
  179. package/lib/features/tools/deletion/delete-tool.js +6 -4
  180. package/lib/features/tools/deletion/delete-tool.js.map +1 -1
  181. package/lib/features/tools/edge-creation/dangling-edge-feedback.d.ts +1 -1
  182. package/lib/features/tools/edge-creation/dangling-edge-feedback.d.ts.map +1 -1
  183. package/lib/features/tools/edge-creation/dangling-edge-feedback.js +7 -5
  184. package/lib/features/tools/edge-creation/dangling-edge-feedback.js.map +1 -1
  185. package/lib/features/tools/edge-creation/edge-creation-tool.js +5 -6
  186. package/lib/features/tools/edge-creation/edge-creation-tool.js.map +1 -1
  187. package/lib/features/tools/edge-creation/view.js +1 -2
  188. package/lib/features/tools/edge-creation/view.js.map +1 -1
  189. package/lib/features/tools/edge-edit/edge-edit-tool-feedback.d.ts +1 -1
  190. package/lib/features/tools/edge-edit/edge-edit-tool-feedback.d.ts.map +1 -1
  191. package/lib/features/tools/edge-edit/edge-edit-tool-feedback.js +8 -5
  192. package/lib/features/tools/edge-edit/edge-edit-tool-feedback.js.map +1 -1
  193. package/lib/features/tools/edge-edit/edge-edit-tool.js +3 -2
  194. package/lib/features/tools/edge-edit/edge-edit-tool.js.map +1 -1
  195. package/lib/features/tools/marquee-selection/marquee-mouse-tool.js +3 -2
  196. package/lib/features/tools/marquee-selection/marquee-mouse-tool.js.map +1 -1
  197. package/lib/features/tools/marquee-selection/marquee-tool-feedback.js +2 -2
  198. package/lib/features/tools/marquee-selection/marquee-tool-feedback.js.map +1 -1
  199. package/lib/features/tools/marquee-selection/marquee-tool.js +3 -2
  200. package/lib/features/tools/marquee-selection/marquee-tool.js.map +1 -1
  201. package/lib/features/tools/marquee-selection/model.d.ts +1 -1
  202. package/lib/features/tools/marquee-selection/model.d.ts.map +1 -1
  203. package/lib/features/tools/marquee-selection/model.js +3 -2
  204. package/lib/features/tools/marquee-selection/model.js.map +1 -1
  205. package/lib/features/tools/node-creation/container-manager.js +3 -4
  206. package/lib/features/tools/node-creation/container-manager.js.map +1 -1
  207. package/lib/features/tools/node-creation/insert-indicator.d.ts +1 -1
  208. package/lib/features/tools/node-creation/insert-indicator.d.ts.map +1 -1
  209. package/lib/features/tools/node-creation/insert-indicator.js +5 -5
  210. package/lib/features/tools/node-creation/insert-indicator.js.map +1 -1
  211. package/lib/features/tools/node-creation/node-creation-tool.js +5 -6
  212. package/lib/features/tools/node-creation/node-creation-tool.js.map +1 -1
  213. package/lib/features/tools/node-creation/node-creation-views.js +1 -2
  214. package/lib/features/tools/node-creation/node-creation-views.js.map +1 -1
  215. package/lib/features/validation/issue-marker.d.ts +2 -2
  216. package/lib/features/validation/issue-marker.d.ts.map +1 -1
  217. package/lib/features/validation/issue-marker.js +7 -2
  218. package/lib/features/validation/issue-marker.js.map +1 -1
  219. package/lib/features/validation/marker-navigator.js +1 -1
  220. package/lib/features/validation/marker-navigator.js.map +1 -1
  221. package/lib/features/validation/validate.js +4 -6
  222. package/lib/features/validation/validate.js.map +1 -1
  223. package/lib/features/viewport/origin-viewport.js +1 -1
  224. package/lib/features/viewport/origin-viewport.js.map +1 -1
  225. package/lib/features/viewport/reposition.js +2 -3
  226. package/lib/features/viewport/reposition.js.map +1 -1
  227. package/lib/features/viewport/viewport-handler.js +2 -3
  228. package/lib/features/viewport/viewport-handler.js.map +1 -1
  229. package/lib/features/viewport/viewport-tool.js +4 -3
  230. package/lib/features/viewport/viewport-tool.js.map +1 -1
  231. package/lib/features/zorder/bring-to-front-command.js +1 -2
  232. package/lib/features/zorder/bring-to-front-command.js.map +1 -1
  233. package/lib/model.js +2 -2
  234. package/lib/model.js.map +1 -1
  235. package/lib/utils/argument-utils.js +5 -5
  236. package/lib/utils/argument-utils.js.map +1 -1
  237. package/lib/utils/gmodel-util.d.ts +13 -1
  238. package/lib/utils/gmodel-util.d.ts.map +1 -1
  239. package/lib/utils/gmodel-util.js +15 -7
  240. package/lib/utils/gmodel-util.js.map +1 -1
  241. package/lib/utils/layout-utils.js +1 -2
  242. package/lib/utils/layout-utils.js.map +1 -1
  243. package/lib/views/glsp-projection-view.js +1 -2
  244. package/lib/views/glsp-projection-view.js.map +1 -1
  245. package/package.json +18 -17
  246. package/src/base/feedback/feedback-command.ts +1 -1
  247. package/src/base/model/glsp-model-source.ts +1 -1
  248. package/src/features/accessibility/README.md +5 -5
  249. package/src/features/accessibility/keyboard-tool-palette/keyboard-tool-palette.ts +1 -1
  250. package/src/features/bounds/glsp-hidden-bounds-updater.ts +133 -60
  251. package/src/features/copy-paste/copy-paste-handler.ts +3 -3
  252. package/src/features/element-template/add-template-element.ts +17 -2
  253. package/src/features/export/glsp-svg-exporter.ts +2 -2
  254. package/src/features/helper-lines/model.ts +4 -5
  255. package/src/features/tool-palette/tool-palette.ts +2 -4
  256. package/src/features/tools/edge-creation/dangling-edge-feedback.ts +4 -2
  257. package/src/features/tools/edge-edit/edge-edit-tool-feedback.ts +5 -3
  258. package/src/features/tools/marquee-selection/model.ts +3 -2
  259. package/src/features/tools/node-creation/insert-indicator.ts +5 -5
  260. package/src/features/validation/issue-marker.ts +7 -2
  261. package/src/utils/gmodel-util.ts +23 -1
  262. package/src/base/action-dispatcher.spec.ts +0 -366
  263. package/src/base/feedback/feedback-emitter.spec.ts +0 -176
  264. package/src/base/model/model-initialization-constraint.spec.ts +0 -95
  265. package/src/base/selection-service.spec.ts +0 -318
  266. package/src/default-modules.spec.ts +0 -56
  267. package/src/features/bounds/freeform-layout.spec.ts +0 -216
  268. package/src/features/bounds/hbox-layout.spec.ts +0 -170
  269. package/src/features/bounds/layouter-test-util.spec.ts +0 -127
  270. package/src/features/bounds/vbox-layout.spec.ts +0 -170
  271. package/src/features/change-bounds/point-position-updater.spec.ts +0 -81
  272. package/src/features/grid/grid-snapper.spec.ts +0 -30
  273. package/src/features/hints/type-hint-provider.spec.ts +0 -360
  274. package/src/features/layout/layout-elements-action.spec.ts +0 -426
  275. package/src/features/navigation/navigation-target-resolver.spec.ts +0 -56
  276. package/src/features/routing/sticky-manhattan-edge-router.spec.ts +0 -212
  277. package/src/features/tools/marquee-selection/marquee-behavior.spec.ts +0 -176
  278. package/src/features/validation/marker-navigator.spec.ts +0 -183
  279. package/src/utils/gmodel-util.spec.ts +0 -221
@@ -25,6 +25,8 @@ import {
25
25
  ElementAndRoutingPoints,
26
26
  GChildElement,
27
27
  GModelElement,
28
+ GModelRoot,
29
+ GRoutableElement,
28
30
  HiddenBoundsUpdater,
29
31
  LayoutData,
30
32
  ModelIndexImpl,
@@ -34,6 +36,8 @@ import {
34
36
  import { inject, injectable, optional } from 'inversify';
35
37
  import { VNode } from 'snabbdom';
36
38
  import { EditorContextService } from '../../base/editor-context-service';
39
+ import { feedbackFeature } from '../../base/feedback/feedback-action-dispatcher';
40
+ import { ServerAction } from '../../base/model/glsp-model-source';
37
41
  import { BoundsAwareModelElement, calcElementAndRoute, getDescendantIds, isRoutable } from '../../utils/gmodel-util';
38
42
  import { LayoutAware } from './layout-data';
39
43
  import { LocalComputedBoundsAction, LocalRequestBoundsAction } from './local-bounds';
@@ -54,87 +58,156 @@ export class GLSPHiddenBoundsUpdater extends HiddenBoundsUpdater {
54
58
 
55
59
  protected element2route: ElementAndRoutingPoints[] = [];
56
60
 
61
+ /**
62
+ * Ids of the routable elements of {@link element2route} that only exist as client-side feedback.
63
+ * Recorded while decorating, as the routes outlive the root they were collected from.
64
+ */
65
+ protected feedbackRouteIds = new Set<string>();
66
+
67
+ /**
68
+ * Root of the hidden rendering currently being collected, used to detect the start of the next
69
+ * one. Referenced weakly, as a hidden root is a throwaway copy of the whole model.
70
+ */
71
+ protected collectingForRoot?: WeakRef<GModelRoot>;
72
+
57
73
  protected getElement2BoundsData(): Map<BoundsAwareModelElement, BoundsDataExt> {
58
74
  return this['element2boundsData'];
59
75
  }
60
76
 
61
77
  override decorate(vnode: VNode, element: GModelElement): VNode {
78
+ this.resetOnNewRendering(element);
62
79
  super.decorate(vnode, element);
63
80
  if (isRoutable(element)) {
64
- this.element2route.push(calcElementAndRoute(element, this.edgeRouterRegistry));
81
+ const route = this.calcElementRoute(element);
82
+ if (route) {
83
+ this.element2route.push(route);
84
+ if (this.isFeedbackElement(element)) {
85
+ this.feedbackRouteIds.add(element.id);
86
+ }
87
+ }
65
88
  }
66
89
  return vnode;
67
90
  }
68
91
 
69
- override postUpdate(cause?: Action): void {
70
- if (cause === undefined || cause.kind !== RequestBoundsAction.KIND) {
71
- return;
72
- }
92
+ /**
93
+ * The route reported for the given element, or `undefined` to leave it out of the
94
+ * {@link ComputedBoundsAction} of this rendering. Override to substitute or to skip a route,
95
+ * which a later rendering reports again as soon as the edge can be routed.
96
+ *
97
+ * A route of fewer than two points, which is how a router reports an edge it cannot route, is
98
+ * skipped: approximating it from the endpoint positions would overwrite the route on the server.
99
+ */
100
+ protected calcElementRoute(element: GRoutableElement): ElementAndRoutingPoints | undefined {
101
+ const elementAndRoute = calcElementAndRoute(element, this.edgeRouterRegistry);
102
+ return (elementAndRoute.newRoutingPoints?.length ?? 0) < 2 ? undefined : elementAndRoute;
103
+ }
73
104
 
74
- if (LocalRequestBoundsAction.is(cause) && cause.elementIDs) {
75
- this.focusOnElements(cause.elementIDs);
105
+ /**
106
+ * Drops the data collected for the previous hidden rendering as soon as a new one starts.
107
+ * {@link postUpdate} cleans up on its way out, but a failing view or vdom patch aborts the
108
+ * rendering before the viewer gets there, leaving the collected bounds behind.
109
+ *
110
+ * Elements are decorated bottom-up, so the rendering is recognized by the root of the element
111
+ * at hand rather than by the root element itself.
112
+ */
113
+ protected resetOnNewRendering(element: GModelElement): void {
114
+ if (this.collectingForRoot?.deref() !== element.root) {
115
+ this.cleanUp();
116
+ this.collectingForRoot = new WeakRef(element.root);
76
117
  }
118
+ }
77
119
 
78
- // collect bounds and layout data in element2BoundsData
79
- this.getBoundsFromDOM();
80
- this.layouter.layout(this.getElement2BoundsData());
81
-
82
- // prepare data for action
83
- const resizes: ElementAndBounds[] = [];
84
- const alignments: ElementAndAlignment[] = [];
85
- const layoutData: ElementAndLayoutData[] = [];
86
- this.getElement2BoundsData().forEach((boundsData, element) => {
87
- if (boundsData.boundsChanged && boundsData.bounds !== undefined) {
88
- const resize: ElementAndBounds = {
89
- elementId: element.id,
90
- newSize: {
91
- width: boundsData.bounds.width,
92
- height: boundsData.bounds.height
93
- }
94
- };
95
- // don't copy position if the element is layouted by the server
96
- if (element instanceof GChildElement && isLayoutContainer(element.parent)) {
97
- resize.newPosition = {
98
- x: boundsData.bounds.x,
99
- y: boundsData.bounds.y
100
- };
101
- }
102
- resizes.push(resize);
120
+ override postUpdate(cause?: Action): void {
121
+ try {
122
+ if (cause === undefined || cause.kind !== RequestBoundsAction.KIND) {
123
+ return;
103
124
  }
104
- if (boundsData.alignmentChanged && boundsData.alignment !== undefined) {
105
- alignments.push({
106
- elementId: element.id,
107
- newAlignment: boundsData.alignment
108
- });
125
+
126
+ if (LocalRequestBoundsAction.is(cause) && cause.elementIDs) {
127
+ this.focusOnElements(cause.elementIDs);
109
128
  }
110
- if (LayoutAware.is(boundsData)) {
111
- layoutData.push({ elementId: element.id, layoutData: boundsData.layoutData });
129
+
130
+ // collect bounds and layout data in element2BoundsData
131
+ this.getBoundsFromDOM();
132
+ this.layouter.layout(this.getElement2BoundsData());
133
+
134
+ // the server can only resolve elements it sent us itself
135
+ const skipFeedback = ServerAction.is(cause);
136
+
137
+ // prepare data for action
138
+ const resizes: ElementAndBounds[] = [];
139
+ const alignments: ElementAndAlignment[] = [];
140
+ const layoutData: ElementAndLayoutData[] = [];
141
+ this.getElement2BoundsData().forEach((boundsData, element) => {
142
+ if (skipFeedback && this.isFeedbackElement(element)) {
143
+ return;
144
+ }
145
+ if (boundsData.boundsChanged && boundsData.bounds !== undefined) {
146
+ const resize: ElementAndBounds = {
147
+ elementId: element.id,
148
+ newSize: {
149
+ width: boundsData.bounds.width,
150
+ height: boundsData.bounds.height
151
+ }
152
+ };
153
+ // don't copy position if the element is layouted by the server
154
+ if (element instanceof GChildElement && isLayoutContainer(element.parent)) {
155
+ resize.newPosition = {
156
+ x: boundsData.bounds.x,
157
+ y: boundsData.bounds.y
158
+ };
159
+ }
160
+ resizes.push(resize);
161
+ }
162
+ if (boundsData.alignmentChanged && boundsData.alignment !== undefined) {
163
+ alignments.push({
164
+ elementId: element.id,
165
+ newAlignment: boundsData.alignment
166
+ });
167
+ }
168
+ if (LayoutAware.is(boundsData)) {
169
+ layoutData.push({ elementId: element.id, layoutData: boundsData.layoutData });
170
+ }
171
+ });
172
+ const relevantRoutes = skipFeedback
173
+ ? this.element2route.filter(route => !this.feedbackRouteIds.has(route.elementId))
174
+ : this.element2route;
175
+ const routes = relevantRoutes.length === 0 ? undefined : relevantRoutes;
176
+
177
+ // prepare and dispatch action
178
+ const responseId = (cause as RequestBoundsAction).requestId;
179
+ const revision = this.root !== undefined ? this.root.revision : undefined;
180
+ const canvasBounds = this.editorContext.canvasBounds;
181
+ const viewport = this.editorContext.viewportData;
182
+ const computedBoundsAction = ComputedBoundsAction.create(resizes, {
183
+ revision,
184
+ alignments,
185
+ layoutData,
186
+ routes,
187
+ responseId,
188
+ canvasBounds,
189
+ viewport
190
+ });
191
+ if (LocalRequestBoundsAction.is(cause)) {
192
+ LocalComputedBoundsAction.mark(computedBoundsAction);
112
193
  }
113
- });
114
- const routes = this.element2route.length === 0 ? undefined : this.element2route;
115
-
116
- // prepare and dispatch action
117
- const responseId = (cause as RequestBoundsAction).requestId;
118
- const revision = this.root !== undefined ? this.root.revision : undefined;
119
- const canvasBounds = this.editorContext.canvasBounds;
120
- const viewport = this.editorContext.viewportData;
121
- const computedBoundsAction = ComputedBoundsAction.create(resizes, {
122
- revision,
123
- alignments,
124
- layoutData,
125
- routes,
126
- responseId,
127
- canvasBounds,
128
- viewport
129
- });
130
- if (LocalRequestBoundsAction.is(cause)) {
131
- LocalComputedBoundsAction.mark(computedBoundsAction);
194
+ this.actionDispatcher.dispatch(computedBoundsAction);
195
+ } finally {
196
+ // always reset collected data so hidden renderings with other causes (e.g. exports/failures) do not leak into the next run
197
+ this.cleanUp();
132
198
  }
133
- this.actionDispatcher.dispatch(computedBoundsAction);
199
+ }
134
200
 
135
- // cleanup
201
+ protected cleanUp(): void {
136
202
  this.getElement2BoundsData().clear();
137
203
  this.element2route = [];
204
+ this.feedbackRouteIds.clear();
205
+ this.collectingForRoot = undefined;
206
+ this.root = undefined;
207
+ }
208
+
209
+ protected isFeedbackElement(element: GModelElement): boolean {
210
+ return element.hasFeature(feedbackFeature);
138
211
  }
139
212
 
140
213
  protected focusOnElements(elementIDs: string[]): void {
@@ -1,5 +1,5 @@
1
1
  /********************************************************************************
2
- * Copyright (c) 2019-2024 EclipseSource and others.
2
+ * Copyright (c) 2019-2026 EclipseSource and others.
3
3
  *
4
4
  * This program and the accompanying materials are made available under the
5
5
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -16,6 +16,7 @@
16
16
  import {
17
17
  ClipboardData,
18
18
  CutOperation,
19
+ generateUuid,
19
20
  IActionDispatcher,
20
21
  PasteOperation,
21
22
  RequestClipboardDataAction,
@@ -24,7 +25,6 @@ import {
24
25
  ViewerOptions
25
26
  } from '@eclipse-glsp/sprotty';
26
27
  import { inject, injectable } from 'inversify';
27
- import { v4 as uuid } from 'uuid';
28
28
  import { EditorContextService } from '../../base/editor-context-service';
29
29
 
30
30
  export interface ICopyPasteHandler {
@@ -107,7 +107,7 @@ export class ServerCopyPasteHandler implements ICopyPasteHandler {
107
107
 
108
108
  handleCopy(event: ClipboardEvent): void {
109
109
  if (event.clipboardData && this.shouldCopy(event)) {
110
- const clipboardId = uuid();
110
+ const clipboardId = generateUuid();
111
111
  event.clipboardData.setData(CLIPBOARD_DATA_FORMAT, toClipboardId(clipboardId));
112
112
  this.actionDispatcher
113
113
  .request<SetClipboardDataAction>(RequestClipboardDataAction.create(this.editorContext.get()))
@@ -1,5 +1,5 @@
1
1
  /********************************************************************************
2
- * Copyright (c) 2023-2024 EclipseSource and others.
2
+ * Copyright (c) 2023-2026 EclipseSource and others.
3
3
  *
4
4
  * This program and the accompanying materials are made available under the
5
5
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -21,14 +21,16 @@ import {
21
21
  ElementTemplate,
22
22
  GChildElement,
23
23
  GModelElementSchema,
24
+ GParentElement,
24
25
  IActionDispatcher,
25
26
  TYPES,
26
27
  distinctAdd,
27
28
  remove
28
29
  } from '@eclipse-glsp/sprotty';
29
30
  import { inject, injectable } from 'inversify';
31
+ import { feedbackFeature } from '../../base/feedback/feedback-action-dispatcher';
30
32
  import { FeedbackCommand } from '../../base/feedback/feedback-command';
31
- import { isNotUndefined } from '../../utils/gmodel-util';
33
+ import { enableFeatures, isNotUndefined } from '../../utils/gmodel-util';
32
34
  import { LocalRequestBoundsAction } from '../bounds/local-bounds';
33
35
 
34
36
  export interface AddTemplateElementsAction extends Action {
@@ -68,12 +70,25 @@ export class AddTemplateElementsFeedbackCommand extends FeedbackCommand {
68
70
  .map(template => templateToSchema(template, context))
69
71
  .filter(isNotUndefined)
70
72
  .map(schema => context.modelFactory.createElement(schema))
73
+ .map(element => this.markAsFeedback(element))
71
74
  .map(element => this.applyRootCssClasses(element, this.action.addClasses, this.action.removeClasses));
72
75
  templateElements.forEach(templateElement => context.root.add(templateElement));
73
76
  const templateElementIDs = templateElements.map(element => element.id);
74
77
  return LocalRequestBoundsAction.fromCommand(context, this.actionDispatcher, this.action, templateElementIDs);
75
78
  }
76
79
 
80
+ /**
81
+ * Marks the given template element as feedback to keep it out of the bounds reported to the
82
+ * server. The bounds pass tests every element on its own, so the whole subtree is marked.
83
+ */
84
+ protected markAsFeedback(element: GChildElement): GChildElement {
85
+ enableFeatures(element, feedbackFeature);
86
+ if (element instanceof GParentElement) {
87
+ element.children.forEach(child => this.markAsFeedback(child));
88
+ }
89
+ return element;
90
+ }
91
+
77
92
  protected applyRootCssClasses(element: GChildElement, addClasses?: string[], removeClasses?: string[]): GChildElement {
78
93
  element.cssClasses = modifyCssClasses(element.cssClasses, addClasses, removeClasses);
79
94
  return element;
@@ -18,6 +18,7 @@ import {
18
18
  Action,
19
19
  ExportSvgAction,
20
20
  ExportSvgOptions,
21
+ generateUuid,
21
22
  GModelRoot,
22
23
  RejectAction,
23
24
  RequestAction,
@@ -25,7 +26,6 @@ import {
25
26
  SvgExporter
26
27
  } from '@eclipse-glsp/sprotty';
27
28
  import { injectable } from 'inversify';
28
- import { v4 as uuid } from 'uuid';
29
29
 
30
30
  @injectable()
31
31
  export class GLSPSvgExporter extends SvgExporter {
@@ -82,7 +82,7 @@ export class GLSPSvgExporter extends SvgExporter {
82
82
  // createSvg requires the svg to have a non-empty id, so we generate one if necessary
83
83
  const originalId = svgElement.id;
84
84
  try {
85
- svgElement.id = originalId || uuid();
85
+ svgElement.id = originalId || generateUuid();
86
86
  return super.createSvg(svgElement, root, options, cause);
87
87
  } finally {
88
88
  svgElement.id = originalId;
@@ -1,5 +1,5 @@
1
1
  /********************************************************************************
2
- * Copyright (c) 2023-2024 EclipseSource and others.
2
+ * Copyright (c) 2023-2026 EclipseSource and others.
3
3
  *
4
4
  * This program and the accompanying materials are made available under the
5
5
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -14,8 +14,7 @@
14
14
  * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
15
  ********************************************************************************/
16
16
 
17
- import { Args, Bounds, Direction, GChildElement, GModelElement, GShapeElement, Point, Vector } from '@eclipse-glsp/sprotty';
18
- import { v4 as uuid } from 'uuid';
17
+ import { Args, Bounds, Direction, GChildElement, GModelElement, GShapeElement, Point, Vector, generateUuid } from '@eclipse-glsp/sprotty';
19
18
  import { ArgsAware } from '../../base/args-feature';
20
19
  import { ResizeHandleLocation } from '../change-bounds/model';
21
20
 
@@ -46,7 +45,7 @@ export class HelperLine extends GChildElement implements ArgsAware {
46
45
  readonly lineType: HelperLineType = HelperLineType.Left
47
46
  ) {
48
47
  super();
49
- this.id = uuid();
48
+ this.id = generateUuid();
50
49
  this.type = HELPER_LINE;
51
50
  }
52
51
 
@@ -86,7 +85,7 @@ export class SelectionBounds extends GShapeElement implements ArgsAware {
86
85
 
87
86
  constructor(bounds?: Bounds) {
88
87
  super();
89
- this.id = uuid();
88
+ this.id = generateUuid();
90
89
  this.type = SELECTION_BOUNDS;
91
90
  if (bounds) {
92
91
  this.bounds = bounds;
@@ -580,11 +580,9 @@ export function createToolGroup(item: PaletteItem): HTMLElement {
580
580
  }
581
581
 
582
582
  export function changeCSSClass(element: Element, css: string): void {
583
- element.classList.contains(css) ? element.classList.remove(css) : element.classList.add(css);
583
+ element.classList.toggle(css);
584
584
  }
585
585
 
586
586
  export function changeCodiconClass(element: Element, codiconId: string): void {
587
- element.classList.contains(codiconCSSClasses(codiconId)[1])
588
- ? element.classList.remove(codiconCSSClasses(codiconId)[1])
589
- : element.classList.add(codiconCSSClasses(codiconId)[1]);
587
+ element.classList.toggle(codiconCSSClasses(codiconId)[1]);
590
588
  }
@@ -1,5 +1,5 @@
1
1
  /********************************************************************************
2
- * Copyright (c) 2019-2024 EclipseSource and others.
2
+ * Copyright (c) 2019-2026 EclipseSource and others.
3
3
  *
4
4
  * This program and the accompanying materials are made available under the
5
5
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -34,7 +34,7 @@ import {
34
34
  import { inject, injectable } from 'inversify';
35
35
  import { feedbackFeature } from '../../../base/feedback/feedback-action-dispatcher';
36
36
  import { FeedbackCommand } from '../../../base/feedback/feedback-command';
37
- import { isRoutable } from '../../../utils/gmodel-util';
37
+ import { enableFeatures, isRoutable } from '../../../utils/gmodel-util';
38
38
  import { toAbsolutePosition } from '../../../utils/viewpoint-util';
39
39
  import { FeedbackEdgeEndView } from './view';
40
40
 
@@ -162,6 +162,8 @@ export function drawFeedbackEdge(
162
162
 
163
163
  const feedbackEdge = context.modelFactory.createElement(edgeSchema);
164
164
  if (isRoutable(feedbackEdge)) {
165
+ // created from the adopter's own edge type, so it needs to be marked as feedback explicitly
166
+ enableFeatures(feedbackEdge, feedbackFeature);
165
167
  edgeEnd.feedbackEdge = feedbackEdge;
166
168
  root.add(edgeEnd);
167
169
  root.add(feedbackEdge);
@@ -1,5 +1,5 @@
1
1
  /********************************************************************************
2
- * Copyright (c) 2019-2024 EclipseSource and others.
2
+ * Copyright (c) 2019-2026 EclipseSource and others.
3
3
  *
4
4
  * This program and the accompanying materials are made available under the
5
5
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -42,10 +42,10 @@ import {
42
42
  } from '@eclipse-glsp/sprotty';
43
43
  import { inject, injectable } from 'inversify';
44
44
  import { DragAwareMouseListener } from '../../../base/drag-aware-mouse-listener';
45
- import { IFeedbackActionDispatcher } from '../../../base/feedback/feedback-action-dispatcher';
45
+ import { IFeedbackActionDispatcher, feedbackFeature } from '../../../base/feedback/feedback-action-dispatcher';
46
46
  import { FeedbackCommand } from '../../../base/feedback/feedback-command';
47
47
  import { FeedbackEmitter } from '../../../base/feedback/feedback-emitter';
48
- import { forEachElement, getMatchingElements, isRoutable, isRoutingHandle } from '../../../utils/gmodel-util';
48
+ import { enableFeatures, forEachElement, getMatchingElements, isRoutable, isRoutingHandle } from '../../../utils/gmodel-util';
49
49
  import { getAbsolutePosition, toAbsoluteBounds } from '../../../utils/viewpoint-util';
50
50
  import { addReconnectHandles, removeReconnectHandles } from '../../reconnect/model';
51
51
  import { IChangeBoundsManager } from '../change-bounds/change-bounds-manager';
@@ -375,6 +375,8 @@ export function drawFeedbackEdgeSource(context: CommandExecutionContext, targetI
375
375
 
376
376
  const feedbackEdge = context.modelFactory.createElement(feedbackEdgeSchema);
377
377
  if (isRoutable(feedbackEdge)) {
378
+ // created from the adopter's own edge type, so it needs to be marked as feedback explicitly
379
+ enableFeatures(feedbackEdge, feedbackFeature);
378
380
  edgeEnd.feedbackEdge = feedbackEdge;
379
381
  root.add(edgeEnd);
380
382
  root.add(feedbackEdge);
@@ -1,5 +1,5 @@
1
1
  /********************************************************************************
2
- * Copyright (c) 2021-2023 EclipseSource and others.
2
+ * Copyright (c) 2021-2026 EclipseSource and others.
3
3
  *
4
4
  * This program and the accompanying materials are made available under the
5
5
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -14,9 +14,10 @@
14
14
  * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
15
  ********************************************************************************/
16
16
  import { boundsFeature, Point, RectangularNode } from '@eclipse-glsp/sprotty';
17
+ import { feedbackFeature } from '../../../base/feedback/feedback-action-dispatcher';
17
18
 
18
19
  export class MarqueeNode extends RectangularNode {
19
- static override readonly DEFAULT_FEATURES = [boundsFeature];
20
+ static override readonly DEFAULT_FEATURES = [boundsFeature, feedbackFeature];
20
21
  startPoint: Point;
21
22
  endPoint: Point;
22
23
  }
@@ -1,5 +1,5 @@
1
1
  /********************************************************************************
2
- * Copyright (c) 2024 EclipseSource and others.
2
+ * Copyright (c) 2024-2026 EclipseSource and others.
3
3
  *
4
4
  * This program and the accompanying materials are made available under the
5
5
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -14,18 +14,18 @@
14
14
  * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
15
  ********************************************************************************/
16
16
 
17
- import { Args, Dimension, FeatureSet, GNode, boundsFeature, createFeatureSet, moveFeature } from '@eclipse-glsp/sprotty';
18
- import { v4 as uuid } from 'uuid';
17
+ import { Args, Dimension, FeatureSet, GNode, boundsFeature, createFeatureSet, generateUuid, moveFeature } from '@eclipse-glsp/sprotty';
19
18
  import { ArgsAware, argsFeature } from '../../../base/args-feature';
19
+ import { feedbackFeature } from '../../../base/feedback/feedback-action-dispatcher';
20
20
 
21
21
  export const ARG_LENGTH = 'length';
22
22
 
23
23
  export class InsertIndicator extends GNode implements ArgsAware {
24
- static override readonly DEFAULT_FEATURES = [boundsFeature, moveFeature, argsFeature];
24
+ static override readonly DEFAULT_FEATURES = [boundsFeature, moveFeature, argsFeature, feedbackFeature];
25
25
 
26
26
  static TYPE = 'node:insert-indicator';
27
27
 
28
- override id: string = uuid();
28
+ override id: string = generateUuid();
29
29
  override type: string = InsertIndicator.TYPE;
30
30
  override features?: FeatureSet = createFeatureSet(InsertIndicator.DEFAULT_FEATURES);
31
31
  override cssClasses: string[] = ['insert-indicator', 'sprotty-node'];
@@ -1,5 +1,5 @@
1
1
  /********************************************************************************
2
- * Copyright (c) 2019-2024 EclipseSource and others.
2
+ * Copyright (c) 2019-2026 EclipseSource and others.
3
3
  *
4
4
  * This program and the accompanying materials are made available under the
5
5
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -25,6 +25,8 @@ import {
25
25
  SIssueMarkerImpl,
26
26
  isBoundsAware
27
27
  } from '@eclipse-glsp/sprotty';
28
+ import { feedbackFeature } from '../../base/feedback/feedback-action-dispatcher';
29
+ import { enableFeatures } from '../../utils/gmodel-util';
28
30
 
29
31
  export class GIssueMarker extends SIssueMarkerImpl implements Projectable {
30
32
  constructor() {
@@ -45,7 +47,7 @@ export class GIssueMarker extends SIssueMarkerImpl implements Projectable {
45
47
  /**
46
48
  * Retrieves the `GIssueMarker` contained by the provided model element as
47
49
  * direct child or a newly instantiated `GIssueMarker` if no child
48
- * `GIssueMarker` exists.
50
+ * `GIssueMarker` exists. A newly created marker is marked as client-side feedback.
49
51
  * @param modelElement for which the `GIssueMarker` should be retrieved or created.
50
52
  * @returns the child `GIssueMarker` or a new `GIssueMarker` if no such child exists.
51
53
  */
@@ -56,6 +58,9 @@ export function getOrCreateGIssueMarker(modelElement: GParentElement): GIssueMar
56
58
 
57
59
  if (issueMarker === undefined) {
58
60
  issueMarker = new GIssueMarker();
61
+ // a marker created here is unknown to the server, so it is kept out of server-bound
62
+ // requests. markers the server sends as part of the model keep reporting their bounds
63
+ enableFeatures(issueMarker, feedbackFeature);
59
64
  if (isBoundsAware(modelElement)) {
60
65
  issueMarker.projectedBounds = modelElement.parentToLocal(modelElement.bounds);
61
66
  }
@@ -1,5 +1,5 @@
1
1
  /********************************************************************************
2
- * Copyright (c) 2019-2025 EclipseSource and others.
2
+ * Copyright (c) 2019-2026 EclipseSource and others.
3
3
  *
4
4
  * This program and the accompanying materials are made available under the
5
5
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -31,6 +31,7 @@ import {
31
31
  RoutedPoint,
32
32
  Selectable,
33
33
  TypeGuard,
34
+ createFeatureSet,
34
35
  distinctAdd,
35
36
  getAbsoluteBounds,
36
37
  getZoom,
@@ -250,6 +251,27 @@ export function toggleCssClass(element: GModelElement, cssClass: string, toggle:
250
251
  return toggle ? addCssClasses(element, cssClass) : removeCssClasses(element, cssClass);
251
252
  }
252
253
 
254
+ /**
255
+ * Enables the given model features on a single {@link GModelElement}.
256
+ *
257
+ * The feature set is shared by all instances of a registered element type, so the element is given
258
+ * a copy of it rather than having the shared one extended. A feature set that is not a `Set` cannot
259
+ * be enumerated and is left untouched.
260
+ *
261
+ * @param element The element for which the features should be enabled.
262
+ * @param features The features to enable.
263
+ */
264
+ export function enableFeatures(element: GModelElement, features: symbol[]): void;
265
+ export function enableFeatures(element: GModelElement, ...features: symbol[]): void;
266
+ export function enableFeatures(element: GModelElement, ...features: symbol[] | [symbol[]]): void {
267
+ const toEnable = Array.isArray(features[0]) ? features[0] : (features as symbol[]);
268
+ if (element.features === undefined) {
269
+ element.features = createFeatureSet(toEnable);
270
+ } else if (element.features instanceof Set) {
271
+ element.features = createFeatureSet([...element.features], { enable: toEnable });
272
+ }
273
+ }
274
+
253
275
  export function isNonRoutableSelectedMovableBoundsAware(element: GModelElement): element is SelectableBoundsAware {
254
276
  return isNonRoutableSelectedBoundsAware(element) && isMoveable(element);
255
277
  }