@eclipse-glsp/client 2.6.0-next.1 → 2.6.0-next.12

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 (174) hide show
  1. package/css/command-palette.css +2 -0
  2. package/css/navigation.css +2 -2
  3. package/css/search.css +12 -3
  4. package/lib/base/auto-complete/auto-complete-widget.d.ts +2 -2
  5. package/lib/base/auto-complete/auto-complete-widget.d.ts.map +1 -1
  6. package/lib/base/auto-complete/auto-complete-widget.js +5 -2
  7. package/lib/base/auto-complete/auto-complete-widget.js.map +1 -1
  8. package/lib/base/auto-complete/autocomplete-suggestion-provider.d.ts +56 -0
  9. package/lib/base/auto-complete/autocomplete-suggestion-provider.d.ts.map +1 -0
  10. package/lib/base/auto-complete/autocomplete-suggestion-provider.js +56 -0
  11. package/lib/base/auto-complete/autocomplete-suggestion-provider.js.map +1 -0
  12. package/lib/base/auto-complete/base-autocomplete-palette.d.ts +4 -9
  13. package/lib/base/auto-complete/base-autocomplete-palette.d.ts.map +1 -1
  14. package/lib/base/auto-complete/base-autocomplete-palette.js +2 -2
  15. package/lib/base/auto-complete/base-autocomplete-palette.js.map +1 -1
  16. package/lib/base/default.module.d.ts.map +1 -1
  17. package/lib/base/default.module.js +4 -0
  18. package/lib/base/default.module.js.map +1 -1
  19. package/lib/base/messages.json +68 -57
  20. package/lib/base/tool-manager/tool-manager.d.ts +2 -2
  21. package/lib/base/tool-manager/tool-manager.d.ts.map +1 -1
  22. package/lib/base/tool-manager/tool-manager.js +4 -4
  23. package/lib/base/tool-manager/tool-manager.js.map +1 -1
  24. package/lib/default-modules.d.ts +1 -1
  25. package/lib/default-modules.d.ts.map +1 -1
  26. package/lib/default-modules.js +4 -1
  27. package/lib/default-modules.js.map +1 -1
  28. package/lib/features/accessibility/accessibility-module.d.ts.map +1 -1
  29. package/lib/features/accessibility/accessibility-module.js +2 -4
  30. package/lib/features/accessibility/accessibility-module.js.map +1 -1
  31. package/lib/features/accessibility/edge-autocomplete/edge-autocomplete-palette.d.ts +21 -15
  32. package/lib/features/accessibility/edge-autocomplete/edge-autocomplete-palette.d.ts.map +1 -1
  33. package/lib/features/accessibility/edge-autocomplete/edge-autocomplete-palette.js +59 -45
  34. package/lib/features/accessibility/edge-autocomplete/edge-autocomplete-palette.js.map +1 -1
  35. package/lib/features/accessibility/element-navigation/diagram-navigation-tool.d.ts.map +1 -1
  36. package/lib/features/accessibility/element-navigation/diagram-navigation-tool.js +2 -3
  37. package/lib/features/accessibility/element-navigation/diagram-navigation-tool.js.map +1 -1
  38. package/lib/features/accessibility/{keyboard-pointer/keyboard-pointer-module.d.ts → keyboard/keyboard-module.d.ts} +2 -2
  39. package/lib/features/accessibility/keyboard/keyboard-module.d.ts.map +1 -0
  40. package/lib/features/accessibility/{keyboard-pointer/keyboard-pointer-module.js → keyboard/keyboard-module.js} +7 -4
  41. package/lib/features/accessibility/keyboard/keyboard-module.js.map +1 -0
  42. package/lib/features/accessibility/keyboard-grid/keyboard-grid-search-palette.d.ts +15 -12
  43. package/lib/features/accessibility/keyboard-grid/keyboard-grid-search-palette.d.ts.map +1 -1
  44. package/lib/features/accessibility/keyboard-grid/keyboard-grid-search-palette.js +40 -22
  45. package/lib/features/accessibility/keyboard-grid/keyboard-grid-search-palette.js.map +1 -1
  46. package/lib/features/accessibility/keyboard-grid/keyboard-node-grid.d.ts +1 -1
  47. package/lib/features/accessibility/keyboard-grid/keyboard-node-grid.js +2 -2
  48. package/lib/features/accessibility/keyboard-grid/keyboard-node-grid.js.map +1 -1
  49. package/lib/features/bounds/glsp-hidden-bounds-updater.d.ts +1 -1
  50. package/lib/features/bounds/glsp-hidden-bounds-updater.d.ts.map +1 -1
  51. package/lib/features/bounds/glsp-hidden-bounds-updater.js +4 -1
  52. package/lib/features/bounds/glsp-hidden-bounds-updater.js.map +1 -1
  53. package/lib/features/change-bounds/movement-restrictor.d.ts +12 -4
  54. package/lib/features/change-bounds/movement-restrictor.d.ts.map +1 -1
  55. package/lib/features/change-bounds/movement-restrictor.js +44 -17
  56. package/lib/features/change-bounds/movement-restrictor.js.map +1 -1
  57. package/lib/features/command-palette/command-palette.d.ts +3 -1
  58. package/lib/features/command-palette/command-palette.d.ts.map +1 -1
  59. package/lib/features/command-palette/command-palette.js +37 -0
  60. package/lib/features/command-palette/command-palette.js.map +1 -1
  61. package/lib/features/context-menu/delete-element-context-menu.d.ts +4 -4
  62. package/lib/features/context-menu/delete-element-context-menu.d.ts.map +1 -1
  63. package/lib/features/context-menu/delete-element-context-menu.js +6 -2
  64. package/lib/features/context-menu/delete-element-context-menu.js.map +1 -1
  65. package/lib/features/context-menu/server-context-menu-provider.d.ts +4 -4
  66. package/lib/features/context-menu/server-context-menu-provider.d.ts.map +1 -1
  67. package/lib/features/context-menu/server-context-menu-provider.js +4 -5
  68. package/lib/features/context-menu/server-context-menu-provider.js.map +1 -1
  69. package/lib/features/copy-paste/copy-paste-context-menu.d.ts +22 -5
  70. package/lib/features/copy-paste/copy-paste-context-menu.d.ts.map +1 -1
  71. package/lib/features/copy-paste/copy-paste-context-menu.js +16 -11
  72. package/lib/features/copy-paste/copy-paste-context-menu.js.map +1 -1
  73. package/lib/features/decoration/decoration-module.d.ts +1 -1
  74. package/lib/features/decoration/decoration-module.d.ts.map +1 -1
  75. package/lib/features/decoration/decoration-module.js +2 -1
  76. package/lib/features/decoration/decoration-module.js.map +1 -1
  77. package/lib/features/decoration/decoration-placer.d.ts +9 -3
  78. package/lib/features/decoration/decoration-placer.d.ts.map +1 -1
  79. package/lib/features/decoration/decoration-placer.js +32 -1
  80. package/lib/features/decoration/decoration-placer.js.map +1 -1
  81. package/{src/features/accessibility/edge-autocomplete/edge-autocomplete-context.ts → lib/features/search-palette/search-palette-key-listener.d.ts} +5 -9
  82. package/lib/features/search-palette/search-palette-key-listener.d.ts.map +1 -0
  83. package/lib/features/search-palette/search-palette-key-listener.js +45 -0
  84. package/lib/features/search-palette/search-palette-key-listener.js.map +1 -0
  85. package/lib/features/{accessibility/search → search-palette}/search-palette-module.d.ts +4 -3
  86. package/lib/features/search-palette/search-palette-module.d.ts.map +1 -0
  87. package/lib/features/search-palette/search-palette-module.js +39 -0
  88. package/lib/features/search-palette/search-palette-module.js.map +1 -0
  89. package/lib/features/search-palette/search-palette.d.ts +51 -0
  90. package/lib/features/search-palette/search-palette.d.ts.map +1 -0
  91. package/lib/features/search-palette/search-palette.js +141 -0
  92. package/lib/features/search-palette/search-palette.js.map +1 -0
  93. package/{src/base/auto-complete/autocomplete-suggestion-providers.ts → lib/features/search-palette/suggestions/edge-element-suggestions.d.ts} +11 -22
  94. package/lib/features/search-palette/suggestions/edge-element-suggestions.d.ts.map +1 -0
  95. package/lib/features/search-palette/suggestions/edge-element-suggestions.js +72 -0
  96. package/lib/features/search-palette/suggestions/edge-element-suggestions.js.map +1 -0
  97. package/lib/features/search-palette/suggestions/named-element-suggestions.d.ts +30 -0
  98. package/lib/features/search-palette/suggestions/named-element-suggestions.d.ts.map +1 -0
  99. package/lib/features/search-palette/suggestions/named-element-suggestions.js +83 -0
  100. package/lib/features/search-palette/suggestions/named-element-suggestions.js.map +1 -0
  101. package/lib/features/validation/marker-navigator.d.ts +3 -3
  102. package/lib/features/validation/marker-navigator.d.ts.map +1 -1
  103. package/lib/features/validation/marker-navigator.js +8 -7
  104. package/lib/features/validation/marker-navigator.js.map +1 -1
  105. package/lib/features/viewport/reposition.d.ts.map +1 -1
  106. package/lib/features/viewport/reposition.js +1 -5
  107. package/lib/features/viewport/reposition.js.map +1 -1
  108. package/lib/index.d.ts +7 -6
  109. package/lib/index.d.ts.map +1 -1
  110. package/lib/index.js +7 -6
  111. package/lib/index.js.map +1 -1
  112. package/lib/standalone-modules.d.ts +1 -1
  113. package/lib/standalone-modules.d.ts.map +1 -1
  114. package/lib/standalone-modules.js +2 -0
  115. package/lib/standalone-modules.js.map +1 -1
  116. package/lib/utils/gmodel-util.d.ts +32 -2
  117. package/lib/utils/gmodel-util.d.ts.map +1 -1
  118. package/lib/utils/gmodel-util.js +29 -1
  119. package/lib/utils/gmodel-util.js.map +1 -1
  120. package/package.json +3 -3
  121. package/src/base/auto-complete/auto-complete-widget.ts +7 -4
  122. package/src/base/auto-complete/autocomplete-suggestion-provider.ts +86 -0
  123. package/src/base/auto-complete/base-autocomplete-palette.ts +6 -6
  124. package/src/base/default.module.ts +5 -0
  125. package/src/base/messages.json +68 -57
  126. package/src/base/tool-manager/tool-manager.ts +4 -4
  127. package/src/default-modules.ts +4 -1
  128. package/src/features/accessibility/accessibility-module.ts +1 -3
  129. package/src/features/accessibility/edge-autocomplete/edge-autocomplete-palette.ts +75 -52
  130. package/src/features/accessibility/element-navigation/diagram-navigation-tool.ts +2 -4
  131. package/src/features/accessibility/{keyboard-pointer/keyboard-pointer-module.ts → keyboard/keyboard-module.ts} +12 -5
  132. package/src/features/accessibility/keyboard-grid/keyboard-grid-search-palette.ts +36 -22
  133. package/src/features/accessibility/keyboard-grid/keyboard-node-grid.ts +3 -3
  134. package/src/features/bounds/glsp-hidden-bounds-updater.ts +5 -1
  135. package/src/features/change-bounds/movement-restrictor.ts +72 -19
  136. package/src/features/command-palette/command-palette.ts +41 -1
  137. package/src/features/context-menu/delete-element-context-menu.ts +9 -5
  138. package/src/features/context-menu/server-context-menu-provider.ts +8 -9
  139. package/src/features/copy-paste/copy-paste-context-menu.ts +21 -17
  140. package/src/features/decoration/decoration-module.ts +2 -1
  141. package/src/features/decoration/decoration-placer.ts +49 -4
  142. package/src/features/{accessibility/search/search-palette-module.ts → search-palette/search-palette-key-listener.ts} +15 -14
  143. package/src/features/search-palette/search-palette-module.ts +48 -0
  144. package/src/features/search-palette/search-palette.ts +164 -0
  145. package/src/features/search-palette/suggestions/edge-element-suggestions.ts +71 -0
  146. package/src/features/search-palette/suggestions/named-element-suggestions.ts +88 -0
  147. package/src/features/validation/marker-navigator.ts +9 -8
  148. package/src/features/viewport/reposition.ts +1 -7
  149. package/src/index.ts +7 -6
  150. package/src/standalone-modules.ts +2 -0
  151. package/src/utils/gmodel-util.ts +59 -1
  152. package/lib/base/auto-complete/autocomplete-suggestion-providers.d.ts +0 -35
  153. package/lib/base/auto-complete/autocomplete-suggestion-providers.d.ts.map +0 -1
  154. package/lib/base/auto-complete/autocomplete-suggestion-providers.js +0 -18
  155. package/lib/base/auto-complete/autocomplete-suggestion-providers.js.map +0 -1
  156. package/lib/features/accessibility/edge-autocomplete/edge-autocomplete-context.d.ts +0 -23
  157. package/lib/features/accessibility/edge-autocomplete/edge-autocomplete-context.d.ts.map +0 -1
  158. package/lib/features/accessibility/edge-autocomplete/edge-autocomplete-context.js +0 -18
  159. package/lib/features/accessibility/edge-autocomplete/edge-autocomplete-context.js.map +0 -1
  160. package/lib/features/accessibility/keyboard-pointer/keyboard-pointer-module.d.ts.map +0 -1
  161. package/lib/features/accessibility/keyboard-pointer/keyboard-pointer-module.js.map +0 -1
  162. package/lib/features/accessibility/search/search-palette-module.d.ts.map +0 -1
  163. package/lib/features/accessibility/search/search-palette-module.js +0 -32
  164. package/lib/features/accessibility/search/search-palette-module.js.map +0 -1
  165. package/lib/features/accessibility/search/search-palette.d.ts +0 -51
  166. package/lib/features/accessibility/search/search-palette.d.ts.map +0 -1
  167. package/lib/features/accessibility/search/search-palette.js +0 -186
  168. package/lib/features/accessibility/search/search-palette.js.map +0 -1
  169. package/lib/features/accessibility/search/search-tool.d.ts +0 -33
  170. package/lib/features/accessibility/search/search-tool.d.ts.map +0 -1
  171. package/lib/features/accessibility/search/search-tool.js +0 -84
  172. package/lib/features/accessibility/search/search-tool.js.map +0 -1
  173. package/src/features/accessibility/search/search-palette.ts +0 -218
  174. package/src/features/accessibility/search/search-tool.ts +0 -74
@@ -1,5 +1,5 @@
1
1
  /********************************************************************************
2
- * Copyright (c) 2023-2024 Business Informatics Group (TU Wien) and others.
2
+ * Copyright (c) 2023-2025 Business Informatics Group (TU Wien) 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
@@ -29,76 +29,89 @@ import {
29
29
  } from '@eclipse-glsp/sprotty';
30
30
  import { injectable } from 'inversify';
31
31
  import { CloseReason, toActionArray } from '../../../base/auto-complete/auto-complete-widget';
32
- import { AutocompleteSuggestion, IAutocompleteSuggestionProvider } from '../../../base/auto-complete/autocomplete-suggestion-providers';
32
+ import { IAutocompleteSuggestionProvider, type AutocompleteSuggestion } from '../../../base/auto-complete/autocomplete-suggestion-provider';
33
33
  import { EnableDefaultToolsAction } from '../../../base/tool-manager/tool';
34
34
  import { GEdge } from '../../../model';
35
- import { SearchAutocompletePalette } from '../search/search-palette';
35
+ import { SearchAutocompletePalette, SearchAutocompleteSuggestion } from '../../search-palette/search-palette';
36
36
  import { SetEdgeTargetSelectionAction } from './action';
37
- import { EdgeAutocompleteContext } from './edge-autocomplete-context';
38
37
 
39
38
  export namespace EdgeAutocompletePaletteMetadata {
40
39
  export const ID = 'edge-autocomplete-palette';
41
40
  }
42
41
 
42
+ export interface EdgeAutocompleteContext {
43
+ role: 'source' | 'target';
44
+ triggerAction: TriggerEdgeCreationAction;
45
+ sourceId?: string;
46
+ targetId?: string;
47
+ }
48
+
49
+ export type EdgeAutocompletePaletteStages = 'initial' | 'source' | 'target' | 'reloading';
50
+
43
51
  @injectable()
44
52
  export class EdgeAutocompletePalette extends SearchAutocompletePalette implements IActionHandler {
45
- protected context?: EdgeAutocompleteContext;
46
-
47
- protected readonly targetSuggestionProvider = new PossibleEdgeTargetAutocompleteSuggestionProvider();
53
+ protected edgeAutocompleteContext?: EdgeAutocompleteContext;
54
+ protected stage: EdgeAutocompletePaletteStages = 'initial';
48
55
 
49
56
  override id(): string {
50
57
  return EdgeAutocompletePaletteMetadata.ID;
51
58
  }
52
59
 
60
+ override get searchContext(): string[] {
61
+ return [EdgeAutocompletePaletteMetadata.ID];
62
+ }
63
+
53
64
  handle(action: Action): Action | void {
54
65
  if (TriggerEdgeCreationAction.is(action)) {
55
- this.context = {
56
- trigger: action,
66
+ this.stage = 'source';
67
+ this.edgeAutocompleteContext = {
68
+ triggerAction: action,
57
69
  role: 'source'
58
70
  };
59
- this.targetSuggestionProvider.setContext(action, this.context);
60
71
  }
61
72
  }
62
73
 
63
74
  protected override onBeforeShow(containerElement: HTMLElement, root: Readonly<GModelRoot>, ...contextElementIds: string[]): void {
64
75
  super.onBeforeShow(containerElement, root, ...contextElementIds);
65
76
 
66
- this.autocompleteWidget.inputField.placeholder = `Search for ${this.context?.role} elements`;
77
+ this.autocompleteWidget.inputField.placeholder = `Search for ${this.edgeAutocompleteContext?.role} elements`;
67
78
  }
68
79
 
69
- protected override getSuggestionProviders(root: Readonly<GModelRoot>, input: string): IAutocompleteSuggestionProvider[] {
70
- return [this.targetSuggestionProvider];
80
+ protected async reload(): Promise<void> {
81
+ this.stage = 'reloading';
82
+ this.hide();
71
83
  }
72
84
 
73
- protected reload(): void {
74
- const context = this.context;
75
- this.hide();
76
- this.context = context;
77
- this.actionDispatcher.dispatch(
78
- SetUIExtensionVisibilityAction.create({
79
- extensionId: EdgeAutocompletePaletteMetadata.ID,
80
- visible: true
81
- })
82
- );
85
+ protected override async provideSearchSuggestions(root: Readonly<GModelRoot>, input: string): Promise<SearchAutocompleteSuggestion[]> {
86
+ return (
87
+ await Promise.all(
88
+ this.suggestionRegistry
89
+ .providersForContext(this.searchContext)
90
+ .flatMap(provider => provider.getSuggestions(root, input, this.edgeAutocompleteContext))
91
+ )
92
+ )
93
+ .flat(1)
94
+ .filter(SearchAutocompleteSuggestion.is);
83
95
  }
84
96
 
85
- protected override executeSuggestion(input: LabeledAction | Action[] | Action): void {
97
+ protected override async executeSuggestion(input: LabeledAction | Action[] | Action): Promise<void> {
86
98
  const action = toActionArray(input)[0] as SetEdgeTargetSelectionAction;
87
99
 
88
- if (this.context?.role === 'source') {
89
- this.context.sourceId = action.elementId;
90
- this.context.role = 'target';
100
+ if (this.edgeAutocompleteContext?.role === 'source') {
101
+ this.edgeAutocompleteContext.sourceId = action.elementId;
102
+ this.edgeAutocompleteContext.role = 'target';
91
103
  this.reload();
92
- } else if (this.context?.role === 'target') {
93
- this.context.targetId = action.elementId;
104
+ } else if (this.edgeAutocompleteContext?.role === 'target') {
105
+ this.edgeAutocompleteContext.targetId = action.elementId;
94
106
  }
95
- if (this.context?.sourceId !== undefined && this.context?.targetId !== undefined) {
96
- this.actionDispatcher.dispatchAll([
107
+
108
+ if (this.edgeAutocompleteContext?.sourceId !== undefined && this.edgeAutocompleteContext?.targetId !== undefined) {
109
+ await this.actionDispatcher.dispatchAll([
97
110
  CreateEdgeOperation.create({
98
- elementTypeId: this.context.trigger.elementTypeId,
99
- sourceElementId: this.context.sourceId,
100
- targetElementId: this.context.targetId,
101
- args: this.context.trigger.args
111
+ elementTypeId: this.edgeAutocompleteContext.triggerAction.elementTypeId,
112
+ sourceElementId: this.edgeAutocompleteContext.sourceId,
113
+ targetElementId: this.edgeAutocompleteContext.targetId,
114
+ args: this.edgeAutocompleteContext.triggerAction.args
102
115
  }),
103
116
  EnableDefaultToolsAction.create()
104
117
  ]);
@@ -107,41 +120,51 @@ export class EdgeAutocompletePalette extends SearchAutocompletePalette implement
107
120
  }
108
121
 
109
122
  protected override autocompleteHide(reason: CloseReason): void {
110
- if (reason !== 'submission') {
123
+ if (this.stage === 'reloading') {
124
+ // Wait until the auto complete is closed before reloading
125
+ if (reason === 'blur') {
126
+ this.actionDispatcher.dispatch(
127
+ SetUIExtensionVisibilityAction.create({
128
+ extensionId: EdgeAutocompletePaletteMetadata.ID,
129
+ visible: true
130
+ })
131
+ );
132
+ this.stage = 'target';
133
+ }
134
+ } else if (reason !== 'submission') {
111
135
  this.hide();
112
136
  }
113
137
  }
114
138
  }
115
139
 
116
140
  @injectable()
117
- export class PossibleEdgeTargetAutocompleteSuggestionProvider implements IAutocompleteSuggestionProvider {
118
- protected proxyEdge?: GEdge;
119
- protected context?: EdgeAutocompleteContext;
120
-
121
- setContext(triggerAction: TriggerEdgeCreationAction, edgeAutocompleteContext: EdgeAutocompleteContext): void {
122
- this.proxyEdge = new GEdge();
123
- this.proxyEdge.type = triggerAction.elementTypeId;
124
- this.context = edgeAutocompleteContext;
125
- }
141
+ export class SetEdgeTargetGridSuggestionProvider implements IAutocompleteSuggestionProvider {
142
+ id = 'glsp.set-edge-target-autocomplete-suggestions';
126
143
 
127
- isAllowedSource(element: GModelElement | undefined, role: 'source' | 'target'): boolean {
128
- return element !== undefined && this.proxyEdge !== undefined && isConnectable(element) && element.canConnect(this.proxyEdge, role);
144
+ canHandle(searchContext: string): boolean {
145
+ return searchContext === EdgeAutocompletePaletteMetadata.ID;
129
146
  }
130
147
 
131
- async retrieveSuggestions(root: Readonly<GModelRoot>, text: string): Promise<AutocompleteSuggestion[]> {
132
- const context = this.context;
133
- if (this.context === undefined) {
148
+ async getSuggestions(root: Readonly<GModelRoot>, text: string, context: EdgeAutocompleteContext): Promise<AutocompleteSuggestion[]> {
149
+ if (context === undefined) {
134
150
  return [];
135
151
  }
136
152
 
137
- const nodes = toArray(root.index.all().filter(element => this.isAllowedSource(element, context!.role))) as GEdge[];
153
+ const proxyEdge = new GEdge();
154
+ proxyEdge.type = context.triggerAction.elementTypeId;
155
+
156
+ const nodes = toArray(root.index.all().filter(element => this.isAllowedSource(proxyEdge, element, context.role))) as GEdge[];
138
157
  return nodes.map(node => ({
139
158
  element: node,
140
159
  action: {
141
160
  label: `[${node.type}] ${name(node) ?? '<no-name>'}`,
142
- actions: [SetEdgeTargetSelectionAction.create(node.id, context!.role)],
161
+ actions: [SetEdgeTargetSelectionAction.create(node.id, context.role)],
143
162
  icon: codiconCSSString('arrow-both')
144
163
  }
145
164
  }));
146
165
  }
166
+
167
+ protected isAllowedSource(proxyEdge: GEdge, element: GModelElement | undefined, role: 'source' | 'target'): boolean {
168
+ return element !== undefined && proxyEdge !== undefined && isConnectable(element) && element.canConnect(proxyEdge, role);
169
+ }
147
170
  }
@@ -38,7 +38,6 @@ import { GEdge } from '../../../model';
38
38
  import { SelectableBoundsAware } from '../../../utils/gmodel-util';
39
39
  import { BaseTool } from '../../tools/base-tools';
40
40
  import { RepositionAction } from '../../viewport/reposition';
41
- import { SearchAutocompletePaletteTool } from '../search/search-tool';
42
41
  import { ShowToastMessageAction } from '../toast/toast-handler';
43
42
  import { ElementNavigator } from './element-navigator';
44
43
 
@@ -144,7 +143,7 @@ export class ElementNavigatorKeyListener extends KeyListener {
144
143
  if (this.mode !== NavigationMode.POSITION) {
145
144
  this.clean();
146
145
  this.tool.dispatchActions([
147
- EnableToolsAction.create([ElementNavigatorTool.ID, SearchAutocompletePaletteTool.ID, AvailableShortcutsTool.ID]),
146
+ EnableToolsAction.create([ElementNavigatorTool.ID, AvailableShortcutsTool.ID]),
148
147
  ShowToastMessageAction.create({
149
148
  id: Symbol.for(ElementNavigatorKeyListener.name),
150
149
  message: messages.navigation.local_navigation_mode_activated
@@ -180,9 +179,8 @@ export class ElementNavigatorKeyListener extends KeyListener {
180
179
  if (this.matchesActivateDefaultNavigation(event)) {
181
180
  if (this.mode !== NavigationMode.DEFAULT) {
182
181
  this.clean();
183
-
184
182
  this.tool.dispatchActions([
185
- EnableToolsAction.create([ElementNavigatorTool.ID, SearchAutocompletePaletteTool.ID, AvailableShortcutsTool.ID]),
183
+ EnableToolsAction.create([ElementNavigatorTool.ID, AvailableShortcutsTool.ID]),
186
184
  ShowToastMessageAction.create({
187
185
  id: Symbol.for(ElementNavigatorKeyListener.name),
188
186
  message: messages.navigation.default_navigation_mode_activated
@@ -1,5 +1,5 @@
1
1
  /********************************************************************************
2
- * Copyright (c) 2023-2024 Business Informatics Group (TU Wien) and others.
2
+ * Copyright (c) 2023-2025 Business Informatics Group (TU Wien) 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
@@ -23,15 +23,19 @@ import {
23
23
  configureActionHandler
24
24
  } from '@eclipse-glsp/sprotty';
25
25
  import { SetEdgeTargetSelectionAction } from '../edge-autocomplete/action';
26
- import { EdgeAutocompletePalette } from '../edge-autocomplete/edge-autocomplete-palette';
26
+ import { EdgeAutocompletePalette, SetEdgeTargetGridSuggestionProvider } from '../edge-autocomplete/edge-autocomplete-palette';
27
27
  import { EdgeAutocompletePaletteTool } from '../edge-autocomplete/edge-autocomplete-tool';
28
28
  import { GlobalKeyListenerTool } from '../global-keylistener-tool';
29
29
  import { EnableKeyboardGridAction, KeyboardGridCellSelectedAction } from '../keyboard-grid/action';
30
30
  import { KeyboardGrid } from '../keyboard-grid/keyboard-grid';
31
- import { GridSearchPalette } from '../keyboard-grid/keyboard-grid-search-palette';
31
+ import {
32
+ GridSearchPalette,
33
+ RevealGridEdgeSuggestionProvider,
34
+ RevealGridNamedElementSuggestionProvider
35
+ } from '../keyboard-grid/keyboard-grid-search-palette';
32
36
  import { KeyboardNodeGrid } from '../keyboard-grid/keyboard-node-grid';
33
- import { SetKeyboardPointerRenderPositionAction } from './actions';
34
- import { KeyboardPointer } from './keyboard-pointer';
37
+ import { SetKeyboardPointerRenderPositionAction } from '../keyboard-pointer/actions';
38
+ import { KeyboardPointer } from '../keyboard-pointer/keyboard-pointer';
35
39
 
36
40
  /**
37
41
  * Handles the pointer used via grid to position new elements.
@@ -55,6 +59,7 @@ export function configureKeyboardControlTools(context: BindingContext): void {
55
59
 
56
60
  bindAsService(context, TYPES.IUIExtension, EdgeAutocompletePalette);
57
61
  bindAsService(context, TYPES.IDefaultTool, EdgeAutocompletePaletteTool);
62
+ bindAsService(context, TYPES.IAutocompleteSuggestionProvider, SetEdgeTargetGridSuggestionProvider);
58
63
 
59
64
  configureActionHandler(context, EnableKeyboardGridAction.KIND, KeyboardGrid);
60
65
  configureActionHandler(context, KeyboardGridCellSelectedAction.KIND, KeyboardPointer);
@@ -63,4 +68,6 @@ export function configureKeyboardControlTools(context: BindingContext): void {
63
68
  configureActionHandler(context, SetEdgeTargetSelectionAction.KIND, EdgeAutocompletePalette);
64
69
 
65
70
  bindAsService(context, TYPES.IUIExtension, GridSearchPalette);
71
+ bindAsService(context, TYPES.IAutocompleteSuggestionProvider, RevealGridEdgeSuggestionProvider);
72
+ bindAsService(context, TYPES.IAutocompleteSuggestionProvider, RevealGridNamedElementSuggestionProvider);
66
73
  }
@@ -1,5 +1,5 @@
1
1
  /********************************************************************************
2
- * Copyright (c) 2023 Business Informatics Group (TU Wien) and others.
2
+ * Copyright (c) 2023-2025 Business Informatics Group (TU Wien) 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
@@ -15,36 +15,40 @@
15
15
  ********************************************************************************/
16
16
  import '../../../../css/keyboard.css';
17
17
 
18
- import { Action, GModelElement, GModelRoot, SetUIExtensionVisibilityAction } from '@eclipse-glsp/sprotty';
18
+ import { Action, GModelElement, SetUIExtensionVisibilityAction } from '@eclipse-glsp/sprotty';
19
19
  import { injectable } from 'inversify';
20
- import { IAutocompleteSuggestionProvider } from '../../../base/auto-complete/autocomplete-suggestion-providers';
21
- import {
22
- RevealEdgeElementAutocompleteSuggestionProvider,
23
- RevealNamedElementAutocompleteSuggestionProvider,
24
- SearchAutocompletePalette
25
- } from '../search/search-palette';
26
- import { KeyboardGridMetadata } from './constants';
27
20
  import { GEdge } from '../../../model';
28
-
29
- export namespace GridSearchPaletteMetadata {
30
- export const ID = 'grid-search-palette';
31
- }
21
+ import { SearchAutocompletePalette } from '../../search-palette/search-palette';
22
+ import { RevealEdgeElementSuggestionProvider } from '../../search-palette/suggestions/edge-element-suggestions';
23
+ import { RevealNamedElementSuggestionProvider } from '../../search-palette/suggestions/named-element-suggestions';
24
+ import { KeyboardGridMetadata } from './constants';
32
25
 
33
26
  @injectable()
34
27
  export class GridSearchPalette extends SearchAutocompletePalette {
28
+ static override readonly ID: string = 'glsp.grid-search-palette';
29
+
35
30
  override id(): string {
36
- return GridSearchPaletteMetadata.ID;
31
+ return GridSearchPalette.ID;
37
32
  }
38
33
 
39
- protected override getSuggestionProviders(root: Readonly<GModelRoot>, input: string): IAutocompleteSuggestionProvider[] {
40
- return [new GridRevealNamedElementSuggestionProvider(), new GridRevealEdgeSuggestionProvider()];
34
+ override get searchContext(): string[] {
35
+ return [GridSearchPalette.ID];
41
36
  }
42
37
  }
43
38
 
44
- export class GridRevealEdgeSuggestionProvider extends RevealEdgeElementAutocompleteSuggestionProvider {
45
- protected override getActions(edge: GEdge): Action[] {
39
+ @injectable()
40
+ export class RevealGridEdgeSuggestionProvider extends RevealEdgeElementSuggestionProvider {
41
+ override get id(): string {
42
+ return 'glsp.reveal-grid-edge-suggestion';
43
+ }
44
+
45
+ override canHandle(searchContext: string): boolean {
46
+ return searchContext === GridSearchPalette.ID;
47
+ }
48
+
49
+ protected override createActions(edge: GEdge): Action[] {
46
50
  return [
47
- ...super.getActions(edge),
51
+ ...super.createActions(edge),
48
52
  SetUIExtensionVisibilityAction.create({
49
53
  extensionId: KeyboardGridMetadata.ID,
50
54
  visible: true
@@ -52,10 +56,20 @@ export class GridRevealEdgeSuggestionProvider extends RevealEdgeElementAutocompl
52
56
  ];
53
57
  }
54
58
  }
55
- export class GridRevealNamedElementSuggestionProvider extends RevealNamedElementAutocompleteSuggestionProvider {
56
- protected override getActions(nameable: GModelElement): Action[] {
59
+
60
+ @injectable()
61
+ export class RevealGridNamedElementSuggestionProvider extends RevealNamedElementSuggestionProvider {
62
+ override get id(): string {
63
+ return 'glsp.reveal-grid-named-element-suggestion';
64
+ }
65
+
66
+ override canHandle(searchContext: string): boolean {
67
+ return searchContext === GridSearchPalette.ID;
68
+ }
69
+
70
+ protected override createActions(nameable: GModelElement): Action[] {
57
71
  return [
58
- ...super.getActions(nameable),
72
+ ...super.createActions(nameable),
59
73
  SetUIExtensionVisibilityAction.create({
60
74
  extensionId: KeyboardGridMetadata.ID,
61
75
  visible: true
@@ -1,5 +1,5 @@
1
1
  /********************************************************************************
2
- * Copyright (c) 2023-2024 Business Informatics Group (TU Wien) and others.
2
+ * Copyright (c) 2023-2025 Business Informatics Group (TU Wien) 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,7 +21,7 @@ import { KeyboardPointerMetadata } from '../keyboard-pointer/constants';
21
21
  import { KeyboardPointer } from '../keyboard-pointer/keyboard-pointer';
22
22
  import { KeyboardNodeGridMetadata } from './constants';
23
23
  import { KeyboardGrid } from './keyboard-grid';
24
- import { GridSearchPaletteMetadata } from './keyboard-grid-search-palette';
24
+ import { GridSearchPalette } from './keyboard-grid-search-palette';
25
25
 
26
26
  @injectable()
27
27
  export class KeyboardNodeGrid extends KeyboardGrid {
@@ -52,7 +52,7 @@ export class KeyboardNodeGrid extends KeyboardGrid {
52
52
  event.preventDefault();
53
53
  this.actionDispatcher.dispatch(
54
54
  SetUIExtensionVisibilityAction.create({
55
- extensionId: GridSearchPaletteMetadata.ID,
55
+ extensionId: GridSearchPalette.ID,
56
56
  visible: true
57
57
  })
58
58
  );
@@ -1,5 +1,5 @@
1
1
  /********************************************************************************
2
- * Copyright (c) 2022-2024 EclipseSource and others.
2
+ * Copyright (c) 2022-2025 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
@@ -65,6 +65,10 @@ export class GLSPHiddenBoundsUpdater extends HiddenBoundsUpdater {
65
65
  }
66
66
 
67
67
  override postUpdate(cause?: Action): void {
68
+ if (cause === undefined || cause.kind !== RequestBoundsAction.KIND) {
69
+ return;
70
+ }
71
+
68
72
  if (LocalRequestBoundsAction.is(cause) && cause.elementIDs) {
69
73
  this.focusOnElements(cause.elementIDs);
70
74
  }
@@ -1,5 +1,5 @@
1
1
  /********************************************************************************
2
- * Copyright (c) 2019-2024 EclipseSource and others.
2
+ * Copyright (c) 2019-2025 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
@@ -13,11 +13,23 @@
13
13
  *
14
14
  * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
15
  ********************************************************************************/
16
- import { Bounds, Dimension, GModelElement, GNode, GParentElement, Point, isBoundsAware, isMoveable } from '@eclipse-glsp/sprotty';
16
+ import {
17
+ Bounds,
18
+ Dimension,
19
+ GChildElement,
20
+ GModelElement,
21
+ GNode,
22
+ GParentElement,
23
+ isBoundsAware,
24
+ isMoveable,
25
+ Point,
26
+ toTypeGuard
27
+ } from '@eclipse-glsp/sprotty';
17
28
  import { injectable } from 'inversify';
18
- import { ModifyCSSFeedbackAction } from '../../base/feedback/css-feedback';
19
- import { BoundsAwareModelElement } from '../../utils/gmodel-util';
29
+ import { CSS_GHOST_ELEMENT, ModifyCSSFeedbackAction } from '../../base/feedback/css-feedback';
30
+ import { BoundsAwareModelElement, getChildren, getParents } from '../../utils/gmodel-util';
20
31
  import { toAbsoluteBounds } from '../../utils/viewpoint-util';
32
+ import { ContainerElement, isContainable } from '../hints/model';
21
33
  import { GResizeHandle } from './model';
22
34
 
23
35
  /**
@@ -39,34 +51,75 @@ export interface IMovementRestrictor {
39
51
  cssClasses?: string[];
40
52
  }
41
53
 
54
+ export interface MoveElementContext {
55
+ element: GModelElement;
56
+ elementAtNewLocation: BoundsAwareModelElement;
57
+ parentContainers: ContainerElement[];
58
+ childNodes: GNode[];
59
+ }
60
+
42
61
  /**
43
62
  * A `IMovementRestrictor` that checks for overlapping elements. Move operations
44
- * are only valid if the element does not collide with another element after moving.
63
+ * are only valid if the element does not collide with another element/node after moving.
45
64
  */
46
65
  @injectable()
47
66
  export class NoOverlapMovementRestrictor implements IMovementRestrictor {
48
67
  cssClasses = ['movement-not-allowed'];
49
68
 
50
69
  validate(element: GModelElement, newLocation?: Point): boolean {
51
- if (!isMoveable(element) || !newLocation) {
70
+ if (!(element instanceof GChildElement) || !isMoveable(element) || !newLocation) {
52
71
  return false;
53
72
  }
54
- // Create ghost element at the newLocation
73
+
74
+ const moveContext = this.createMoveElementContext(element, newLocation);
75
+ const elementsToValidate = Array.from(element.root.index.all()).filter(e =>
76
+ this.isBoundsRelevant(e, moveContext)
77
+ ) as BoundsAwareModelElement[];
78
+
79
+ const valid = !elementsToValidate.some(e => this.areOverlapping(e, moveContext.elementAtNewLocation));
80
+ return valid;
81
+ }
82
+
83
+ protected createMoveElementContext(element: GModelElement, newLocation: Point): MoveElementContext {
84
+ const parentContainers = getParents(element, isContainable);
85
+ const childNodes = getChildren(element, toTypeGuard(GNode));
86
+ // Create a mock element at the newLocation for overlap checking
55
87
  const dimensions: Dimension = isBoundsAware(element) ? element.bounds : { width: 1, height: 1 };
56
- const ghostElement = Object.create(element) as BoundsAwareModelElement;
57
- ghostElement.bounds = { ...dimensions, ...newLocation };
58
- ghostElement.type = 'Ghost';
59
- ghostElement.id = element.id;
60
- return !Array.from(
61
- element.root.index
62
- .all()
63
- .filter(node => node.id !== ghostElement.id && node !== ghostElement.root && node instanceof GNode)
64
- .map(node => node as BoundsAwareModelElement)
65
- ).some(e => this.areOverlapping(e, ghostElement));
88
+ const elementAtNewLocation = Object.create(element) as BoundsAwareModelElement as BoundsAwareModelElement;
89
+ elementAtNewLocation.bounds = { ...dimensions, ...newLocation };
90
+
91
+ return {
92
+ element,
93
+ elementAtNewLocation,
94
+ parentContainers,
95
+ childNodes
96
+ };
66
97
  }
67
98
 
68
- protected isBoundsRelevant(element: GModelElement, ghostElement: BoundsAwareModelElement): element is BoundsAwareModelElement {
69
- return element.id !== ghostElement.id && element !== ghostElement.root && element instanceof GNode && isBoundsAware(element);
99
+ protected isBoundsRelevant(element: GModelElement, moveContext: MoveElementContext): element is BoundsAwareModelElement {
100
+ // Only consider GNodes that are not the element being moved (or one of its children)
101
+ if (
102
+ !(element instanceof GNode) ||
103
+ element.id === moveContext.element.id ||
104
+ moveContext.childNodes.some(child => child.id === element.id)
105
+ ) {
106
+ return false;
107
+ }
108
+
109
+ // Do not consider parent containers of the element being moved
110
+ if (moveContext.parentContainers.length > 0 && moveContext.parentContainers.some(container => container.id === element.id)) {
111
+ return false;
112
+ }
113
+
114
+ // If the element is a ghost element (node creation), don't consider overlap checks for potential parent containers
115
+ if (
116
+ moveContext.element.cssClasses?.includes(CSS_GHOST_ELEMENT) &&
117
+ isContainable(element) &&
118
+ element.isContainableElement(moveContext.element.type)
119
+ ) {
120
+ return false;
121
+ }
122
+ return true;
70
123
  }
71
124
 
72
125
  protected areOverlapping(element1: BoundsAwareModelElement, element2: BoundsAwareModelElement): boolean {
@@ -14,14 +14,16 @@
14
14
  * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
15
  ********************************************************************************/
16
16
 
17
- import { CommandPalette } from '@eclipse-glsp/sprotty';
17
+ import { Bounds, CommandPalette, getWindowScroll, GModelElement, GModelRoot } from '@eclipse-glsp/sprotty';
18
18
  import { injectable } from 'inversify';
19
19
  import { CSS_HIDDEN_EXTENSION_CLASS, CSS_UI_EXTENSION_CLASS } from '../../base/ui-extension/ui-extension';
20
+ import { getElements, isSelectableAndBoundsAware } from '../../utils/gmodel-util';
20
21
 
21
22
  @injectable()
22
23
  export class GlspCommandPalette extends CommandPalette {
23
24
  protected override initializeContents(containerElement: HTMLElement): void {
24
25
  super.initializeContents(containerElement);
26
+ containerElement.style.position = '';
25
27
  containerElement.classList.add(CSS_UI_EXTENSION_CLASS);
26
28
  }
27
29
 
@@ -32,4 +34,42 @@ export class GlspCommandPalette extends CommandPalette {
32
34
  this.containerElement?.classList.add(CSS_HIDDEN_EXTENSION_CLASS);
33
35
  }
34
36
  }
37
+
38
+ protected override onBeforeShow(containerElement: HTMLElement, root: Readonly<GModelRoot>, ...selectedElementIds: string[]): void {
39
+ let x = this.xOffset;
40
+ let y = this.yOffset;
41
+
42
+ const selectedElements = getElements(root.index, selectedElementIds, isSelectableAndBoundsAware);
43
+ if (selectedElements.length === 1) {
44
+ const bounds = this.getAbsoluteBounds(selectedElements[0]);
45
+ x += bounds.x + bounds.width;
46
+ y += bounds.y;
47
+ } else {
48
+ const bounds = this.getAbsoluteBounds(root);
49
+ x += bounds.x;
50
+ y += bounds.y;
51
+ }
52
+ containerElement.style.left = `${x}px`;
53
+ containerElement.style.top = `${y}px`;
54
+ containerElement.style.width = `${this.defaultWidth}px`;
55
+ }
56
+
57
+ protected getAbsoluteBounds(element: Readonly<GModelElement>): Bounds {
58
+ let x = 0;
59
+ let y = 0;
60
+ let width = 0;
61
+ let height = 0;
62
+
63
+ const svgElementId = this.domHelper.createUniqueDOMElementId(element);
64
+ const svgElement = document.getElementById(svgElementId);
65
+ if (svgElement) {
66
+ const rect = svgElement.getBoundingClientRect();
67
+ const scroll = getWindowScroll();
68
+ x = rect.left + scroll.x;
69
+ y = rect.top + scroll.y;
70
+ width = rect.width;
71
+ height = rect.height;
72
+ }
73
+ return { x, y, width, height };
74
+ }
35
75
  }
@@ -1,5 +1,5 @@
1
1
  /********************************************************************************
2
- * Copyright (c) 2019-2024 EclipseSource and others.
2
+ * Copyright (c) 2019-2025 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
@@ -13,9 +13,10 @@
13
13
  *
14
14
  * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
15
  ********************************************************************************/
16
- import { DeleteElementOperation, GModelRoot, IContextMenuItemProvider, MenuItem, Point, TYPES } from '@eclipse-glsp/sprotty';
16
+ import { ClientMenuItem, DeleteElementOperation, GModelRoot, IContextMenuItemProvider, Point, TYPES } from '@eclipse-glsp/sprotty';
17
17
  import { inject, injectable } from 'inversify';
18
18
  import { EditorContextService, EditorContextServiceProvider } from '../../base/editor-context-service';
19
+ import { messages } from '../../base/messages';
19
20
 
20
21
  @injectable()
21
22
  export class DeleteElementContextMenuItemProvider implements IContextMenuItemProvider {
@@ -26,14 +27,17 @@ export class DeleteElementContextMenuItemProvider implements IContextMenuItemPro
26
27
  @inject(EditorContextService)
27
28
  protected editorContext: EditorContextService;
28
29
 
29
- async getItems(_root: Readonly<GModelRoot>, _lastMousePosition?: Point): Promise<MenuItem[]> {
30
+ async getItems(_root: Readonly<GModelRoot>, _lastMousePosition?: Point): Promise<ClientMenuItem[]> {
31
+ if (this.editorContext.isReadonly) {
32
+ return [];
33
+ }
30
34
  return [this.createDeleteMenuItem()];
31
35
  }
32
36
 
33
- protected createDeleteMenuItem(): MenuItem {
37
+ protected createDeleteMenuItem(): ClientMenuItem {
34
38
  return {
35
39
  id: 'delete',
36
- label: 'Delete',
40
+ label: messages.context_menu.delete,
37
41
  sortString: 'd',
38
42
  group: 'edit',
39
43
  actions: [DeleteElementOperation.create(this.editorContext.selectedElements.map(e => e.id))],