@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) 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
@@ -14,11 +14,11 @@
14
14
  * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
15
  ********************************************************************************/
16
16
  import {
17
- Action,
17
+ ClientMenuItem,
18
18
  GModelElement,
19
19
  IActionDispatcher,
20
20
  IContextMenuItemProvider,
21
- LabeledAction,
21
+ MenuItem,
22
22
  Point,
23
23
  RequestContextActions,
24
24
  SetContextActions,
@@ -37,7 +37,7 @@ export class ServerContextMenuItemProvider implements IContextMenuItemProvider {
37
37
  @inject(TYPES.IActionDispatcher) protected actionDispatcher: IActionDispatcher;
38
38
  @inject(EditorContextService) protected editorContext: EditorContextService;
39
39
 
40
- async getItems(root: Readonly<GModelElement>, _lastMousePosition?: Point): Promise<LabeledAction[]> {
40
+ async getItems(root: Readonly<GModelElement>, _lastMousePosition?: Point): Promise<ClientMenuItem[]> {
41
41
  const selectedElementIds = Array.from(
42
42
  root.index
43
43
  .all()
@@ -50,10 +50,9 @@ export class ServerContextMenuItemProvider implements IContextMenuItemProvider {
50
50
  return response ? this.getContextActionsFromResponse(response) : [];
51
51
  }
52
52
 
53
- getContextActionsFromResponse(action: Action): LabeledAction[] {
54
- if (SetContextActions.is(action)) {
55
- return action.actions;
56
- }
57
- return [];
53
+ getContextActionsFromResponse(action: SetContextActions): ClientMenuItem[] {
54
+ return action.actions
55
+ .filter(item => MenuItem.is(item)) //
56
+ .map(item => ClientMenuItem.convert(item));
58
57
  }
59
58
  }
@@ -1,5 +1,5 @@
1
1
  /********************************************************************************
2
- * Copyright (c) 2020-2023 EclipseSource and others.
2
+ * Copyright (c) 2020-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
@@ -14,21 +14,23 @@
14
14
  * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
15
  ********************************************************************************/
16
16
  /* eslint-disable deprecation/deprecation */
17
- import { inject, injectable } from 'inversify';
18
17
  import {
19
18
  Action,
19
+ ClientMenuItem,
20
+ GModelRoot,
20
21
  IActionDispatcher,
21
22
  IActionHandler,
22
23
  IContextMenuItemProvider,
23
- MenuItem,
24
- Point,
25
- GModelRoot,
26
24
  MessageAction,
25
+ Point,
27
26
  StatusAction,
28
27
  TYPES,
29
28
  hasStringProp,
30
29
  isSelected
31
30
  } from '@eclipse-glsp/sprotty';
31
+ import { inject, injectable } from 'inversify';
32
+ import { EditorContextService } from '../../base/editor-context-service';
33
+ import { messages } from '../../base/messages';
32
34
 
33
35
  /**
34
36
  * An `InvokeCopyPasteAction` is dispatched by the client to initiate a cut, copy or paste operation.
@@ -89,39 +91,41 @@ export class InvokeCopyPasteActionHandler implements IActionHandler {
89
91
 
90
92
  @injectable()
91
93
  export class CopyPasteContextMenuItemProvider implements IContextMenuItemProvider {
92
- getItems(root: Readonly<GModelRoot>, _lastMousePosition?: Point): Promise<MenuItem[]> {
94
+ @inject(EditorContextService)
95
+ protected editorContext: EditorContextService;
96
+
97
+ async getItems(root: Readonly<GModelRoot>, _lastMousePosition?: Point): Promise<ClientMenuItem[]> {
98
+ if (this.editorContext.isReadonly) {
99
+ return [];
100
+ }
93
101
  const hasSelectedElements = Array.from(root.index.all().filter(isSelected)).length > 0;
94
- return Promise.resolve([
95
- this.createCopyMenuItem(hasSelectedElements),
96
- this.createCutMenuItem(hasSelectedElements),
97
- this.createPasteMenuItem()
98
- ]);
102
+ return [this.createCopyMenuItem(hasSelectedElements), this.createCutMenuItem(hasSelectedElements), this.createPasteMenuItem()];
99
103
  }
100
104
 
101
- protected createPasteMenuItem(): MenuItem {
105
+ protected createPasteMenuItem(): ClientMenuItem {
102
106
  return {
103
107
  id: 'paste',
104
- label: 'Paste',
108
+ label: messages.context_menu.paste,
105
109
  group: 'copy-paste',
106
110
  actions: [InvokeCopyPasteAction.create('paste')],
107
111
  isEnabled: () => true
108
112
  };
109
113
  }
110
114
 
111
- protected createCutMenuItem(hasSelectedElements: boolean): MenuItem {
115
+ protected createCutMenuItem(hasSelectedElements: boolean): ClientMenuItem {
112
116
  return {
113
117
  id: 'cut',
114
- label: 'Cut',
118
+ label: messages.context_menu.cut,
115
119
  group: 'copy-paste',
116
120
  actions: [InvokeCopyPasteAction.create('cut')],
117
121
  isEnabled: () => hasSelectedElements
118
122
  };
119
123
  }
120
124
 
121
- protected createCopyMenuItem(hasSelectedElements: boolean): MenuItem {
125
+ protected createCopyMenuItem(hasSelectedElements: boolean): ClientMenuItem {
122
126
  return {
123
127
  id: 'copy',
124
- label: 'Copy',
128
+ label: messages.context_menu.copy,
125
129
  group: 'copy-paste',
126
130
  actions: [InvokeCopyPasteAction.create('copy')],
127
131
  isEnabled: () => hasSelectedElements
@@ -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
@@ -20,6 +20,7 @@ import { GlspDecorationPlacer } from './decoration-placer';
20
20
  export const decorationModule = new FeatureModule(
21
21
  bind => {
22
22
  bindAsService(bind, TYPES.IVNodePostprocessor, GlspDecorationPlacer);
23
+ bind(TYPES.ISvgExportPostprocessor).toService(GlspDecorationPlacer);
23
24
  },
24
25
  { featureId: Symbol('decoration') }
25
26
  );
@@ -1,5 +1,5 @@
1
1
  /********************************************************************************
2
- * Copyright (c) 2019-2023 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,12 +13,37 @@
13
13
  *
14
14
  * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
15
  ********************************************************************************/
16
- import { Decoration, DecorationPlacer, GChildElement, GModelElement, GRoutableElement, Point, isSizeable } from '@eclipse-glsp/sprotty';
17
- import { injectable } from 'inversify';
16
+ import {
17
+ Action,
18
+ DOMHelper,
19
+ Decoration,
20
+ DecorationPlacer,
21
+ GChildElement,
22
+ GModelElement,
23
+ GRoutableElement,
24
+ ISvgExportPostProcessor,
25
+ LazyInjector,
26
+ Point,
27
+ TYPES,
28
+ isDecoration,
29
+ isSizeable
30
+ } from '@eclipse-glsp/sprotty';
31
+ import { inject, injectable } from 'inversify';
32
+ import { EditorContextService } from '../../base/editor-context-service';
33
+ import { filter } from '../../utils/gmodel-util';
18
34
 
19
35
  @injectable()
20
- export class GlspDecorationPlacer extends DecorationPlacer {
36
+ export class GlspDecorationPlacer extends DecorationPlacer implements ISvgExportPostProcessor {
21
37
  protected static readonly DECORATION_OFFSET: Point = { x: 12, y: 10 };
38
+ @inject(TYPES.DOMHelper)
39
+ protected domHelper: DOMHelper;
40
+
41
+ @inject(LazyInjector)
42
+ protected lazyInjector: LazyInjector;
43
+
44
+ get editorContextService(): EditorContextService {
45
+ return this.lazyInjector.get(EditorContextService);
46
+ }
22
47
 
23
48
  protected override getPosition(element: GModelElement & Decoration): Point {
24
49
  if (element instanceof GChildElement && element.parent instanceof GRoutableElement) {
@@ -32,4 +57,24 @@ export class GlspDecorationPlacer extends DecorationPlacer {
32
57
  }
33
58
  return Point.ORIGIN;
34
59
  }
60
+ // HiddenVNodePostprocessor implementation
61
+ override postUpdate(cause?: Action): void;
62
+ // ISvgExportPostProcessor implementation
63
+ override postUpdate(element: SVGSVGElement, cause?: Action): void;
64
+ override postUpdate(elementOrCause?: SVGSVGElement | Action, _cause?: Action): void {
65
+ // Called as HiddenVNodePostprocessor => no-op
66
+ if (!elementOrCause || Action.is(elementOrCause)) {
67
+ return;
68
+ }
69
+
70
+ // Called as ISvgExportPostProcessor
71
+ // Adjust the position of all decorations in the exported SVG
72
+ const svg = elementOrCause;
73
+ const translate = `translate(-${GlspDecorationPlacer.DECORATION_OFFSET.x}px, -${GlspDecorationPlacer.DECORATION_OFFSET.y}px)`;
74
+ filter(this.editorContextService.modelRoot.index, isDecoration).forEach(decoration => {
75
+ const domId = this.domHelper.createUniqueDOMElementId(decoration);
76
+ const element = svg.querySelector<SVGElement>(`#${domId}`);
77
+ element!.style.transform = translate;
78
+ });
79
+ }
35
80
  }
@@ -14,20 +14,21 @@
14
14
  * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
15
  ********************************************************************************/
16
16
 
17
- import { bindAsService, BindingContext, FeatureModule, TYPES } from '@eclipse-glsp/sprotty';
18
- import '../../../../css/search.css';
17
+ import { Action, GModelElement, KeyListener, matchesKeystroke, SetUIExtensionVisibilityAction } from '@eclipse-glsp/sprotty';
18
+ import { injectable } from 'inversify';
19
19
  import { SearchAutocompletePalette } from './search-palette';
20
- import { SearchAutocompletePaletteTool } from './search-tool';
21
20
 
22
- export const searchPaletteModule = new FeatureModule(
23
- (bind, _unbind, isBound, rebind) => {
24
- const context = { bind, isBound, rebind };
25
- configureSearchPaletteModule(context);
26
- },
27
- { featureId: Symbol('searchPalette') }
28
- );
29
-
30
- export function configureSearchPaletteModule(context: Pick<BindingContext, 'bind'>): void {
31
- bindAsService(context, TYPES.IUIExtension, SearchAutocompletePalette);
32
- bindAsService(context, TYPES.IDefaultTool, SearchAutocompletePaletteTool);
21
+ @injectable()
22
+ export class SearchPaletteKeyListener extends KeyListener {
23
+ override keyDown(element: GModelElement, event: KeyboardEvent): Action[] {
24
+ if (matchesKeystroke(event, 'KeyF', 'ctrlCmd')) {
25
+ return [
26
+ SetUIExtensionVisibilityAction.create({
27
+ extensionId: SearchAutocompletePalette.ID,
28
+ visible: true
29
+ })
30
+ ];
31
+ }
32
+ return [];
33
+ }
33
34
  }
@@ -0,0 +1,48 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2023-2025 Business Informatics Group (TU Wien) and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the Eclipse Public License v. 2.0 which is available at
6
+ * http://www.eclipse.org/legal/epl-2.0.
7
+ *
8
+ * This Source Code may also be made available under the following Secondary
9
+ * Licenses when the conditions for such availability set forth in the Eclipse
10
+ * Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ * with the GNU Classpath Exception which is available at
12
+ * https://www.gnu.org/software/classpath/license.html.
13
+ *
14
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
+ ********************************************************************************/
16
+
17
+ import { bindAsService, FeatureModule, TYPES } from '@eclipse-glsp/sprotty';
18
+ import '../../../css/search.css';
19
+ import { SearchAutocompletePalette } from './search-palette';
20
+ import { SearchPaletteKeyListener } from './search-palette-key-listener';
21
+ import { RevealEdgeElementSuggestionProvider } from './suggestions/edge-element-suggestions';
22
+ import { NodesWithoutNameSuggestionProvider, RevealNamedElementSuggestionProvider } from './suggestions/named-element-suggestions';
23
+
24
+ export const searchPaletteModule = new FeatureModule(
25
+ (bind, _unbind, isBound, rebind) => {
26
+ const context = { bind, isBound, rebind };
27
+ bindAsService(context, TYPES.IUIExtension, SearchAutocompletePalette);
28
+ },
29
+ { featureId: Symbol('searchPalette') }
30
+ );
31
+
32
+ export const searchPaletteDefaultSuggestionsModule = new FeatureModule(
33
+ (bind, _unbind, isBound, rebind) => {
34
+ const context = { bind, isBound, rebind };
35
+ bindAsService(context, TYPES.IAutocompleteSuggestionProvider, RevealNamedElementSuggestionProvider);
36
+ bindAsService(context, TYPES.IAutocompleteSuggestionProvider, NodesWithoutNameSuggestionProvider);
37
+ bindAsService(context, TYPES.IAutocompleteSuggestionProvider, RevealEdgeElementSuggestionProvider);
38
+ },
39
+ { featureId: Symbol('searchPaletteDefaultSuggestions'), requires: searchPaletteModule }
40
+ );
41
+
42
+ export const standaloneSearchPaletteModule = new FeatureModule(
43
+ (bind, _unbind, isBound) => {
44
+ const context = { bind, isBound };
45
+ bindAsService(context, TYPES.KeyListener, SearchPaletteKeyListener);
46
+ },
47
+ { featureId: Symbol('standaloneSearchPalette'), requires: searchPaletteModule }
48
+ );
@@ -0,0 +1,164 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2023-2025 Business Informatics Group (TU Wien) and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the Eclipse Public License v. 2.0 which is available at
6
+ * http://www.eclipse.org/legal/epl-2.0.
7
+ *
8
+ * This Source Code may also be made available under the following Secondary
9
+ * Licenses when the conditions for such availability set forth in the Eclipse
10
+ * Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ * with the GNU Classpath Exception which is available at
12
+ * https://www.gnu.org/software/classpath/license.html.
13
+ *
14
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
+ ********************************************************************************/
16
+
17
+ import { GModelElement, GModelRoot, GNode, LabeledAction, SelectAllAction, toArray, TYPES } from '@eclipse-glsp/sprotty';
18
+ import { inject, injectable } from 'inversify';
19
+ import { debounce, isEqual } from 'lodash';
20
+ import {
21
+ AutocompleteSuggestionProviderContext,
22
+ type AutocompleteSuggestion,
23
+ type AutocompleteSuggestionRegistry
24
+ } from '../../base/auto-complete/autocomplete-suggestion-provider';
25
+ import { BaseAutocompletePalette } from '../../base/auto-complete/base-autocomplete-palette';
26
+ import { applyCssClasses, deleteCssClasses } from '../../base/feedback/css-feedback';
27
+ import { messages } from '../../base/messages';
28
+ import { GEdge } from '../../model';
29
+ import { RepositionAction } from '../viewport/reposition';
30
+
31
+ const CSS_SEARCH_HIDDEN = 'search-hidden';
32
+ const CSS_SEARCH_HIGHLIGHTED = 'search-highlighted';
33
+
34
+ export interface SearchAutocompleteSuggestion extends Required<AutocompleteSuggestion> {}
35
+
36
+ export namespace SearchAutocompleteSuggestion {
37
+ export function is(suggestion: AutocompleteSuggestion): suggestion is SearchAutocompleteSuggestion {
38
+ return suggestion.element !== undefined;
39
+ }
40
+ }
41
+
42
+ @injectable()
43
+ export class SearchAutocompletePalette extends BaseAutocompletePalette {
44
+ static readonly ID: string = 'glsp.search-autocomplete-palette';
45
+
46
+ @inject(TYPES.IAutocompleteSuggestionProviderRegistry)
47
+ protected readonly suggestionRegistry: AutocompleteSuggestionRegistry;
48
+
49
+ /**
50
+ * Cache the suggestions so that we don't have to retrieve them again for CSS manipulation.
51
+ */
52
+ protected cachedSuggestions: SearchAutocompleteSuggestion[] = [];
53
+
54
+ id(): string {
55
+ return SearchAutocompletePalette.ID;
56
+ }
57
+
58
+ /**
59
+ * The search context for the search palette. This is used to filter the suggestions
60
+ */
61
+ get searchContext(): string[] {
62
+ return [AutocompleteSuggestionProviderContext.CANVAS];
63
+ }
64
+
65
+ protected override initializeContents(containerElement: HTMLElement): void {
66
+ super.initializeContents(containerElement);
67
+
68
+ this.autocompleteWidget.inputField.placeholder = messages.search.placeholder;
69
+ containerElement.setAttribute('aria-label', messages.search.label);
70
+ }
71
+
72
+ protected async retrieveSuggestions(root: Readonly<GModelRoot>, input: string): Promise<LabeledAction[]> {
73
+ const suggestions = await this.provideSearchSuggestions(root, input);
74
+ this.cachedSuggestions = suggestions;
75
+ return suggestions.map(s => s.action);
76
+ }
77
+
78
+ protected async provideSearchSuggestions(root: Readonly<GModelRoot>, input: string): Promise<SearchAutocompleteSuggestion[]> {
79
+ return (
80
+ await Promise.all(
81
+ this.suggestionRegistry.providersForContext(this.searchContext).flatMap(provider => provider.getSuggestions(root, input))
82
+ )
83
+ )
84
+ .flat(1)
85
+ .filter(SearchAutocompleteSuggestion.is);
86
+ }
87
+
88
+ protected override async visibleSuggestionsChanged(root: Readonly<GModelRoot>, labeledActions: LabeledAction[]): Promise<void> {
89
+ await this.applyCSS(this.getHiddenElements(root, this.getSuggestionsFromLabeledActions(labeledActions)), CSS_SEARCH_HIDDEN);
90
+ await this.deleteCSS(
91
+ this.getSuggestionsFromLabeledActions(labeledActions)
92
+ .filter(s => s.element)
93
+ .map(s => s.element!),
94
+ CSS_SEARCH_HIDDEN
95
+ );
96
+ }
97
+
98
+ protected override async selectedSuggestionChanged(
99
+ root: Readonly<GModelRoot>,
100
+ labeledAction?: LabeledAction | undefined
101
+ ): Promise<void> {
102
+ await this.handleSuggestionChanged(root, labeledAction);
103
+ }
104
+
105
+ protected readonly handleSuggestionChanged = debounce(this.doHandleSuggestionChanged, 300, { trailing: true });
106
+ protected async doHandleSuggestionChanged(root: Readonly<GModelRoot>, labeledAction?: LabeledAction | undefined): Promise<void> {
107
+ await this.deleteAllCSS(root, CSS_SEARCH_HIGHLIGHTED);
108
+ if (labeledAction !== undefined) {
109
+ const suggestions = this.getSuggestionsFromLabeledActions([labeledAction]);
110
+
111
+ const actions: RepositionAction[] = [];
112
+ suggestions.map(currElem => actions.push(RepositionAction.create([currElem.element.id])));
113
+
114
+ this.actionDispatcher.dispatchAll(actions);
115
+ await this.applyCSS(
116
+ suggestions.map(s => s.element),
117
+ CSS_SEARCH_HIGHLIGHTED
118
+ );
119
+ }
120
+ }
121
+
122
+ override show(root: Readonly<GModelRoot>, ...contextElementIds: string[]): void {
123
+ this.actionDispatcher.dispatch(SelectAllAction.create(false));
124
+
125
+ super.show(root, ...contextElementIds);
126
+ }
127
+
128
+ override hide(): void {
129
+ if (this.root !== undefined) {
130
+ this.deleteAllCSS(this.root, CSS_SEARCH_HIDDEN, CSS_SEARCH_HIGHLIGHTED);
131
+ this.autocompleteWidget.inputField.value = '';
132
+ }
133
+
134
+ super.hide();
135
+ }
136
+
137
+ protected applyCSS(elements: GModelElement[], ...add: string[]): Promise<void> {
138
+ const actions = elements.map(element => applyCssClasses(element, ...add));
139
+ return this.actionDispatcher.dispatchAll(actions);
140
+ }
141
+
142
+ protected deleteCSS(elements: GModelElement[], ...remove: string[]): Promise<void> {
143
+ const actions = elements.map(element => deleteCssClasses(element, ...remove));
144
+ return this.actionDispatcher.dispatchAll(actions);
145
+ }
146
+
147
+ protected deleteAllCSS(root: Readonly<GModelRoot>, ...remove: string[]): Promise<void> {
148
+ const actions = toArray(root.index.all().map(element => deleteCssClasses(element, ...remove)));
149
+ return this.actionDispatcher.dispatchAll(actions);
150
+ }
151
+
152
+ protected getSuggestionsFromLabeledActions(labeledActions: LabeledAction[]): SearchAutocompleteSuggestion[] {
153
+ return this.cachedSuggestions.filter(c => labeledActions.find(s => isEqual(s, c.action)));
154
+ }
155
+
156
+ protected getHiddenElements(root: Readonly<GModelRoot>, suggestions: SearchAutocompleteSuggestion[]): GModelElement[] {
157
+ return toArray(
158
+ root.index
159
+ .all()
160
+ .filter(element => element instanceof GNode || element instanceof GEdge)
161
+ .filter(element => suggestions.find(suggestion => suggestion.element.id === element.id) === undefined)
162
+ );
163
+ }
164
+ }
@@ -0,0 +1,71 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2023-2025 Business Informatics Group (TU Wien) and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the Eclipse Public License v. 2.0 which is available at
6
+ * http://www.eclipse.org/legal/epl-2.0.
7
+ *
8
+ * This Source Code may also be made available under the following Secondary
9
+ * Licenses when the conditions for such availability set forth in the Eclipse
10
+ * Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ * with the GNU Classpath Exception which is available at
12
+ * https://www.gnu.org/software/classpath/license.html.
13
+ *
14
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
+ ********************************************************************************/
16
+
17
+ import { Action, CenterAction, GModelRoot, SelectAction, codiconCSSString, name, toArray } from '@eclipse-glsp/sprotty';
18
+ import { injectable } from 'inversify';
19
+ import {
20
+ AutocompleteSuggestionProviderContext,
21
+ IAutocompleteSuggestionProvider,
22
+ type AutocompleteSuggestion
23
+ } from '../../../base/auto-complete/autocomplete-suggestion-provider';
24
+ import { GEdge } from '../../../model';
25
+
26
+ @injectable()
27
+ export class RevealEdgeElementSuggestionProvider implements IAutocompleteSuggestionProvider {
28
+ get id(): string {
29
+ return 'glsp.reveal-edge-element-suggestion';
30
+ }
31
+
32
+ canHandle(context: string): boolean {
33
+ return context === AutocompleteSuggestionProviderContext.CANVAS;
34
+ }
35
+
36
+ async getSuggestions(root: Readonly<GModelRoot>, text: string): Promise<AutocompleteSuggestion[]> {
37
+ const edges = toArray(root.index.all().filter(element => element instanceof GEdge)) as GEdge[];
38
+ return edges.map(edge => ({
39
+ element: edge,
40
+ action: {
41
+ label: `[${edge.type}] ${this.getEdgeLabel(root, edge)}`,
42
+ actions: this.createActions(edge),
43
+ icon: codiconCSSString('arrow-both')
44
+ }
45
+ }));
46
+ }
47
+
48
+ protected createActions(edge: GEdge): Action[] {
49
+ return [
50
+ SelectAction.create({ selectedElementsIDs: [edge.id] }),
51
+ CenterAction.create([edge.sourceId, edge.targetId], { retainZoom: true })
52
+ ];
53
+ }
54
+
55
+ protected getEdgeLabel(root: Readonly<GModelRoot>, edge: GEdge): string {
56
+ let sourceName = '';
57
+ let targetName = '';
58
+
59
+ const sourceNode = root.index.getById(edge.sourceId);
60
+ const targetNode = root.index.getById(edge.targetId);
61
+
62
+ if (sourceNode !== undefined) {
63
+ sourceName = name(sourceNode) ?? sourceNode.type;
64
+ }
65
+ if (targetNode !== undefined) {
66
+ targetName = name(targetNode) ?? targetNode.type;
67
+ }
68
+
69
+ return sourceName + ' -> ' + targetName;
70
+ }
71
+ }
@@ -0,0 +1,88 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2023-2025 Business Informatics Group (TU Wien) and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the Eclipse Public License v. 2.0 which is available at
6
+ * http://www.eclipse.org/legal/epl-2.0.
7
+ *
8
+ * This Source Code may also be made available under the following Secondary
9
+ * Licenses when the conditions for such availability set forth in the Eclipse
10
+ * Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ * with the GNU Classpath Exception which is available at
12
+ * https://www.gnu.org/software/classpath/license.html.
13
+ *
14
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
+ ********************************************************************************/
16
+
17
+ import {
18
+ Action,
19
+ CenterAction,
20
+ codiconCSSString,
21
+ GModelElement,
22
+ GModelRoot,
23
+ GNode,
24
+ isNameable,
25
+ name,
26
+ SelectAction,
27
+ toArray
28
+ } from '@eclipse-glsp/sprotty';
29
+ import { injectable } from 'inversify';
30
+ import {
31
+ AutocompleteSuggestionProviderContext,
32
+ IAutocompleteSuggestionProvider,
33
+ type AutocompleteSuggestion
34
+ } from '../../../base/auto-complete/autocomplete-suggestion-provider';
35
+
36
+ @injectable()
37
+ export class RevealNamedElementSuggestionProvider implements IAutocompleteSuggestionProvider {
38
+ get id(): string {
39
+ return 'glsp.reveal-named-element-suggestion';
40
+ }
41
+
42
+ canHandle(context: string): boolean {
43
+ return context === AutocompleteSuggestionProviderContext.CANVAS;
44
+ }
45
+
46
+ async getSuggestions(root: Readonly<GModelRoot>, text: string): Promise<AutocompleteSuggestion[]> {
47
+ const nameables = toArray(root.index.all().filter(element => isNameable(element)));
48
+ return nameables.map(nameable => ({
49
+ element: nameable,
50
+ action: {
51
+ label: `[${nameable.type}] ${name(nameable) ?? '<no-name>'}`,
52
+ actions: this.createActions(nameable),
53
+ icon: codiconCSSString('eye')
54
+ }
55
+ }));
56
+ }
57
+
58
+ protected createActions(nameable: GModelElement): Action[] {
59
+ return [SelectAction.create({ selectedElementsIDs: [nameable.id] }), CenterAction.create([nameable.id], { retainZoom: true })];
60
+ }
61
+ }
62
+
63
+ @injectable()
64
+ export class NodesWithoutNameSuggestionProvider implements IAutocompleteSuggestionProvider {
65
+ get id(): string {
66
+ return 'glsp.reveal-nodes-without-name-suggestion';
67
+ }
68
+
69
+ canHandle(searchContext: string): boolean {
70
+ return searchContext === AutocompleteSuggestionProviderContext.CANVAS;
71
+ }
72
+
73
+ async getSuggestions(root: Readonly<GModelRoot>, text: string): Promise<AutocompleteSuggestion[]> {
74
+ const nodes = toArray(root.index.all().filter(element => !isNameable(element) && element instanceof GNode));
75
+ return nodes.map(node => ({
76
+ element: node,
77
+ action: {
78
+ label: `[${node.type}]`,
79
+ actions: this.createActions(node),
80
+ icon: codiconCSSString('symbol-namespace')
81
+ }
82
+ }));
83
+ }
84
+
85
+ protected createActions(nameable: GModelElement): Action[] {
86
+ return [SelectAction.create({ selectedElementsIDs: [nameable.id] }), CenterAction.create([nameable.id], { retainZoom: true })];
87
+ }
88
+ }