@theia/core 1.62.0-next.3 → 1.62.1

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 (244) hide show
  1. package/README.md +7 -7
  2. package/i18n/nls.cs.json +158 -13
  3. package/i18n/nls.de.json +158 -13
  4. package/i18n/nls.es.json +158 -13
  5. package/i18n/nls.fr.json +158 -13
  6. package/i18n/nls.hu.json +158 -13
  7. package/i18n/nls.it.json +158 -13
  8. package/i18n/nls.ja.json +158 -13
  9. package/i18n/nls.json +159 -14
  10. package/i18n/nls.ko.json +158 -13
  11. package/i18n/nls.pl.json +158 -13
  12. package/i18n/nls.pt-br.json +158 -13
  13. package/i18n/nls.ru.json +158 -13
  14. package/i18n/nls.tr.json +158 -13
  15. package/i18n/nls.zh-cn.json +158 -13
  16. package/i18n/nls.zh-tw.json +158 -13
  17. package/lib/browser/catalog.json +206 -33
  18. package/lib/browser/common-frontend-contribution.d.ts +1 -1
  19. package/lib/browser/common-frontend-contribution.d.ts.map +1 -1
  20. package/lib/browser/common-frontend-contribution.js +13 -11
  21. package/lib/browser/common-frontend-contribution.js.map +1 -1
  22. package/lib/browser/context-menu-renderer.d.ts +14 -3
  23. package/lib/browser/context-menu-renderer.d.ts.map +1 -1
  24. package/lib/browser/context-menu-renderer.js +23 -1
  25. package/lib/browser/context-menu-renderer.js.map +1 -1
  26. package/lib/browser/frontend-application-module.d.ts.map +1 -1
  27. package/lib/browser/frontend-application-module.js +1 -3
  28. package/lib/browser/frontend-application-module.js.map +1 -1
  29. package/lib/browser/hover-service.d.ts.map +1 -1
  30. package/lib/browser/hover-service.js +7 -0
  31. package/lib/browser/hover-service.js.map +1 -1
  32. package/lib/browser/menu/action-menu-node.d.ts +36 -0
  33. package/lib/browser/menu/action-menu-node.d.ts.map +1 -0
  34. package/lib/browser/menu/action-menu-node.js +113 -0
  35. package/lib/browser/menu/action-menu-node.js.map +1 -0
  36. package/lib/browser/menu/browser-context-menu-renderer.d.ts +12 -4
  37. package/lib/browser/menu/browser-context-menu-renderer.d.ts.map +1 -1
  38. package/lib/browser/menu/browser-context-menu-renderer.js +12 -13
  39. package/lib/browser/menu/browser-context-menu-renderer.js.map +1 -1
  40. package/lib/browser/menu/browser-menu-module.d.ts.map +1 -1
  41. package/lib/browser/menu/browser-menu-module.js +4 -0
  42. package/lib/browser/menu/browser-menu-module.js.map +1 -1
  43. package/lib/browser/menu/browser-menu-node-factory.d.ts +13 -0
  44. package/lib/browser/menu/browser-menu-node-factory.d.ts.map +1 -0
  45. package/lib/browser/menu/browser-menu-node-factory.js +54 -0
  46. package/lib/browser/menu/browser-menu-node-factory.js.map +1 -0
  47. package/lib/browser/menu/browser-menu-plugin.d.ts +12 -30
  48. package/lib/browser/menu/browser-menu-plugin.d.ts.map +1 -1
  49. package/lib/browser/menu/browser-menu-plugin.js +78 -159
  50. package/lib/browser/menu/browser-menu-plugin.js.map +1 -1
  51. package/lib/browser/menu/composite-menu-node.d.ts +49 -0
  52. package/lib/browser/menu/composite-menu-node.d.ts.map +1 -0
  53. package/lib/browser/menu/composite-menu-node.js +127 -0
  54. package/lib/browser/menu/composite-menu-node.js.map +1 -0
  55. package/lib/browser/menu/menu.spec.d.ts.map +1 -0
  56. package/lib/{common → browser}/menu/menu.spec.js +38 -13
  57. package/lib/browser/menu/menu.spec.js.map +1 -0
  58. package/lib/browser/open-with-service.d.ts +1 -1
  59. package/lib/browser/saveable-service.d.ts.map +1 -1
  60. package/lib/browser/saveable-service.js +6 -1
  61. package/lib/browser/saveable-service.js.map +1 -1
  62. package/lib/browser/shell/application-shell.d.ts +7 -5
  63. package/lib/browser/shell/application-shell.d.ts.map +1 -1
  64. package/lib/browser/shell/application-shell.js +82 -28
  65. package/lib/browser/shell/application-shell.js.map +1 -1
  66. package/lib/browser/shell/index.d.ts +1 -0
  67. package/lib/browser/shell/index.d.ts.map +1 -1
  68. package/lib/browser/shell/index.js +1 -0
  69. package/lib/browser/shell/index.js.map +1 -1
  70. package/lib/browser/shell/sidebar-bottom-menu-widget.d.ts.map +1 -1
  71. package/lib/browser/shell/sidebar-bottom-menu-widget.js +2 -1
  72. package/lib/browser/shell/sidebar-bottom-menu-widget.js.map +1 -1
  73. package/lib/browser/shell/sidebar-menu-widget.d.ts +4 -1
  74. package/lib/browser/shell/sidebar-menu-widget.d.ts.map +1 -1
  75. package/lib/browser/shell/sidebar-menu-widget.js +14 -1
  76. package/lib/browser/shell/sidebar-menu-widget.js.map +1 -1
  77. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.d.ts +66 -8
  78. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.d.ts.map +1 -1
  79. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.js +161 -8
  80. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.js.map +1 -1
  81. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.d.ts +18 -32
  82. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.d.ts.map +1 -1
  83. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.js +52 -88
  84. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.js.map +1 -1
  85. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-types.d.ts +17 -21
  86. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-types.d.ts.map +1 -1
  87. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-types.js +9 -9
  88. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-types.js.map +1 -1
  89. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.d.ts +7 -39
  90. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.d.ts.map +1 -1
  91. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.js +30 -238
  92. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.js.map +1 -1
  93. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.spec.js +13 -13
  94. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.spec.js.map +1 -1
  95. package/lib/browser/shell/tab-bar-toolbar/tab-toolbar-item.d.ts +56 -0
  96. package/lib/browser/shell/tab-bar-toolbar/tab-toolbar-item.d.ts.map +1 -0
  97. package/lib/browser/shell/tab-bar-toolbar/tab-toolbar-item.js +208 -0
  98. package/lib/browser/shell/tab-bar-toolbar/tab-toolbar-item.js.map +1 -0
  99. package/lib/browser/shell/tab-bars.d.ts.map +1 -1
  100. package/lib/browser/shell/tab-bars.js +2 -1
  101. package/lib/browser/shell/tab-bars.js.map +1 -1
  102. package/lib/browser/shell/theia-dock-panel.d.ts +4 -10
  103. package/lib/browser/shell/theia-dock-panel.d.ts.map +1 -1
  104. package/lib/browser/shell/theia-dock-panel.js +7 -84
  105. package/lib/browser/shell/theia-dock-panel.js.map +1 -1
  106. package/lib/browser/shell/theia-split-panel.d.ts +6 -0
  107. package/lib/browser/shell/theia-split-panel.d.ts.map +1 -0
  108. package/lib/browser/shell/theia-split-panel.js +56 -0
  109. package/lib/browser/shell/theia-split-panel.js.map +1 -0
  110. package/lib/browser/tree/tree-widget.d.ts +1 -0
  111. package/lib/browser/tree/tree-widget.d.ts.map +1 -1
  112. package/lib/browser/tree/tree-widget.js +6 -0
  113. package/lib/browser/tree/tree-widget.js.map +1 -1
  114. package/lib/browser/view-container.d.ts +6 -3
  115. package/lib/browser/view-container.d.ts.map +1 -1
  116. package/lib/browser/view-container.js +36 -26
  117. package/lib/browser/view-container.js.map +1 -1
  118. package/lib/browser/window/default-secondary-window-service.d.ts +1 -0
  119. package/lib/browser/window/default-secondary-window-service.d.ts.map +1 -1
  120. package/lib/browser/window/default-secondary-window-service.js +3 -0
  121. package/lib/browser/window/default-secondary-window-service.js.map +1 -1
  122. package/lib/common/listener.d.ts +21 -0
  123. package/lib/common/listener.d.ts.map +1 -0
  124. package/lib/common/listener.js +81 -0
  125. package/lib/common/listener.js.map +1 -0
  126. package/lib/common/listener.spec.d.ts +2 -0
  127. package/lib/common/listener.spec.d.ts.map +1 -0
  128. package/lib/common/listener.spec.js +255 -0
  129. package/lib/common/listener.spec.js.map +1 -0
  130. package/lib/common/menu/index.d.ts +2 -3
  131. package/lib/common/menu/index.d.ts.map +1 -1
  132. package/lib/common/menu/index.js +2 -3
  133. package/lib/common/menu/index.js.map +1 -1
  134. package/lib/common/menu/menu-model-registry.d.ts +37 -50
  135. package/lib/common/menu/menu-model-registry.d.ts.map +1 -1
  136. package/lib/common/menu/menu-model-registry.js +176 -225
  137. package/lib/common/menu/menu-model-registry.js.map +1 -1
  138. package/lib/common/menu/menu-types.d.ts +58 -96
  139. package/lib/common/menu/menu-types.d.ts.map +1 -1
  140. package/lib/common/menu/menu-types.js +43 -39
  141. package/lib/common/menu/menu-types.js.map +1 -1
  142. package/lib/common/messaging/proxy-factory.d.ts.map +1 -1
  143. package/lib/common/messaging/proxy-factory.js +4 -0
  144. package/lib/common/messaging/proxy-factory.js.map +1 -1
  145. package/lib/electron-browser/menu/electron-context-menu-renderer.d.ts +15 -5
  146. package/lib/electron-browser/menu/electron-context-menu-renderer.d.ts.map +1 -1
  147. package/lib/electron-browser/menu/electron-context-menu-renderer.js +21 -14
  148. package/lib/electron-browser/menu/electron-context-menu-renderer.js.map +1 -1
  149. package/lib/electron-browser/menu/electron-main-menu-factory.d.ts +4 -16
  150. package/lib/electron-browser/menu/electron-main-menu-factory.d.ts.map +1 -1
  151. package/lib/electron-browser/menu/electron-main-menu-factory.js +84 -104
  152. package/lib/electron-browser/menu/electron-main-menu-factory.js.map +1 -1
  153. package/lib/electron-browser/menu/electron-menu-contribution.d.ts.map +1 -1
  154. package/lib/electron-browser/menu/electron-menu-contribution.js +1 -4
  155. package/lib/electron-browser/menu/electron-menu-contribution.js.map +1 -1
  156. package/lib/electron-browser/menu/electron-menu-module.d.ts.map +1 -1
  157. package/lib/electron-browser/menu/electron-menu-module.js +5 -0
  158. package/lib/electron-browser/menu/electron-menu-module.js.map +1 -1
  159. package/lib/electron-browser/window/electron-secondary-window-service.d.ts +1 -0
  160. package/lib/electron-browser/window/electron-secondary-window-service.d.ts.map +1 -1
  161. package/lib/electron-browser/window/electron-secondary-window-service.js +20 -0
  162. package/lib/electron-browser/window/electron-secondary-window-service.js.map +1 -1
  163. package/lib/electron-browser/window/electron-window-service.d.ts +3 -0
  164. package/lib/electron-browser/window/electron-window-service.d.ts.map +1 -1
  165. package/lib/electron-browser/window/electron-window-service.js +10 -1
  166. package/lib/electron-browser/window/electron-window-service.js.map +1 -1
  167. package/lib/electron-main/theia-electron-window.d.ts.map +1 -1
  168. package/lib/electron-main/theia-electron-window.js +2 -0
  169. package/lib/electron-main/theia-electron-window.js.map +1 -1
  170. package/package.json +7 -8
  171. package/src/browser/common-frontend-contribution.ts +14 -14
  172. package/src/browser/context-menu-renderer.ts +33 -5
  173. package/src/browser/frontend-application-module.ts +1 -7
  174. package/src/browser/hover-service.ts +7 -0
  175. package/src/browser/menu/action-menu-node.ts +128 -0
  176. package/src/browser/menu/browser-context-menu-renderer.ts +18 -11
  177. package/src/browser/menu/browser-menu-module.ts +4 -0
  178. package/src/browser/menu/browser-menu-node-factory.ts +48 -0
  179. package/src/browser/menu/browser-menu-plugin.ts +80 -168
  180. package/src/browser/menu/composite-menu-node.ts +140 -0
  181. package/src/{common → browser}/menu/menu.spec.ts +47 -15
  182. package/src/browser/open-with-service.ts +1 -1
  183. package/src/browser/saveable-service.ts +6 -1
  184. package/src/browser/shell/application-shell.ts +91 -29
  185. package/src/browser/shell/index.ts +1 -0
  186. package/src/browser/shell/sidebar-bottom-menu-widget.tsx +2 -1
  187. package/src/browser/shell/sidebar-menu-widget.tsx +12 -2
  188. package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.tsx +239 -0
  189. package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.ts +59 -102
  190. package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar-types.ts +14 -23
  191. package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar.spec.ts +14 -14
  192. package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar.tsx +34 -261
  193. package/src/browser/shell/tab-bar-toolbar/tab-toolbar-item.tsx +251 -0
  194. package/src/browser/shell/tab-bars.ts +2 -1
  195. package/src/browser/shell/theia-dock-panel.ts +10 -91
  196. package/src/browser/shell/theia-split-panel.ts +56 -0
  197. package/src/browser/style/hover-service.css +6 -1
  198. package/src/browser/style/index.css +3 -11
  199. package/src/browser/style/view-container.css +17 -31
  200. package/src/browser/tree/tree-widget.tsx +7 -0
  201. package/src/browser/view-container.ts +51 -30
  202. package/src/browser/window/default-secondary-window-service.ts +4 -0
  203. package/src/common/listener.spec.ts +315 -0
  204. package/src/common/listener.ts +88 -0
  205. package/src/common/menu/index.ts +2 -3
  206. package/src/common/menu/menu-model-registry.ts +187 -230
  207. package/src/common/menu/menu-types.ts +82 -128
  208. package/src/common/messaging/proxy-factory.ts +4 -1
  209. package/src/electron-browser/menu/electron-context-menu-renderer.ts +29 -13
  210. package/src/electron-browser/menu/electron-main-menu-factory.ts +92 -116
  211. package/src/electron-browser/menu/electron-menu-contribution.ts +1 -4
  212. package/src/electron-browser/menu/electron-menu-module.ts +6 -1
  213. package/src/electron-browser/window/electron-secondary-window-service.ts +22 -0
  214. package/src/electron-browser/window/electron-window-service.ts +11 -1
  215. package/src/electron-main/theia-electron-window.ts +2 -0
  216. package/lib/common/menu/action-menu-node.d.ts +0 -20
  217. package/lib/common/menu/action-menu-node.d.ts.map +0 -1
  218. package/lib/common/menu/action-menu-node.js +0 -57
  219. package/lib/common/menu/action-menu-node.js.map +0 -1
  220. package/lib/common/menu/composite-menu-node.d.ts +0 -47
  221. package/lib/common/menu/composite-menu-node.d.ts.map +0 -1
  222. package/lib/common/menu/composite-menu-node.js +0 -96
  223. package/lib/common/menu/composite-menu-node.js.map +0 -1
  224. package/lib/common/menu/composite-menu-node.spec.d.ts +0 -2
  225. package/lib/common/menu/composite-menu-node.spec.d.ts.map +0 -1
  226. package/lib/common/menu/composite-menu-node.spec.js +0 -68
  227. package/lib/common/menu/composite-menu-node.spec.js.map +0 -1
  228. package/lib/common/menu/menu-adapter.d.ts +0 -36
  229. package/lib/common/menu/menu-adapter.d.ts.map +0 -1
  230. package/lib/common/menu/menu-adapter.js +0 -93
  231. package/lib/common/menu/menu-adapter.js.map +0 -1
  232. package/lib/common/menu/menu.spec.d.ts.map +0 -1
  233. package/lib/common/menu/menu.spec.js.map +0 -1
  234. package/lib/common/test/mock-menu.d.ts +0 -8
  235. package/lib/common/test/mock-menu.d.ts.map +0 -1
  236. package/lib/common/test/mock-menu.js +0 -35
  237. package/lib/common/test/mock-menu.js.map +0 -1
  238. package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.ts +0 -31
  239. package/src/common/menu/action-menu-node.ts +0 -65
  240. package/src/common/menu/composite-menu-node.spec.ts +0 -67
  241. package/src/common/menu/composite-menu-node.ts +0 -116
  242. package/src/common/menu/menu-adapter.ts +0 -103
  243. package/src/common/test/mock-menu.ts +0 -35
  244. /package/lib/{common → browser}/menu/menu.spec.d.ts +0 -0
@@ -16,14 +16,16 @@
16
16
 
17
17
  import { inject, injectable, postConstruct } from 'inversify';
18
18
  import * as React from 'react';
19
- import { ContextKeyService, ContextMatcher } from '../../context-key-service';
20
- import { CommandRegistry, Disposable, DisposableCollection, MenuCommandExecutor, MenuModelRegistry, MenuPath, nls } from '../../../common';
19
+ import { ContextKeyService } from '../../context-key-service';
20
+ import { CommandRegistry, Disposable, DisposableCollection, nls } from '../../../common';
21
21
  import { Anchor, ContextMenuAccess, ContextMenuRenderer } from '../../context-menu-renderer';
22
- import { LabelIcon, LabelParser } from '../../label-parser';
23
- import { ACTION_ITEM, codicon, ReactWidget, Widget } from '../../widgets';
22
+ import { LabelParser } from '../../label-parser';
23
+ import { codicon, ReactWidget, Widget } from '../../widgets';
24
24
  import { TabBarToolbarRegistry } from './tab-bar-toolbar-registry';
25
- import { ReactTabBarToolbarItem, TabBarDelegator, TabBarToolbarItem, TAB_BAR_TOOLBAR_CONTEXT_MENU, RenderedToolbarItem } from './tab-bar-toolbar-types';
25
+ import { TabBarDelegator, TabBarToolbarAction } from './tab-bar-toolbar-types';
26
26
  import { KeybindingRegistry } from '../..//keybinding';
27
+ import { TabBarToolbarItem } from './tab-toolbar-item';
28
+ import { GroupImpl, MenuModelRegistry } from '../../../common/menu';
27
29
 
28
30
  /**
29
31
  * Factory for instantiating tab-bar toolbars.
@@ -33,10 +35,10 @@ export interface TabBarToolbarFactory {
33
35
  (): TabBarToolbar;
34
36
  }
35
37
 
36
- /**
37
- * Class name indicating rendering of a toolbar item without an icon but instead with a text label.
38
- */
39
- const NO_ICON_CLASS = 'no-icon';
38
+ export function toAnchor(event: React.MouseEvent): Anchor {
39
+ const itemBox = event.currentTarget.closest('.' + TabBarToolbar.Styles.TAB_BAR_TOOLBAR_ITEM)?.getBoundingClientRect();
40
+ return itemBox ? { y: itemBox.bottom, x: itemBox.left } : event.nativeEvent;
41
+ }
40
42
 
41
43
  /**
42
44
  * Tab-bar toolbar widget representing the active [tab-bar toolbar items](TabBarToolbarItem).
@@ -45,7 +47,7 @@ const NO_ICON_CLASS = 'no-icon';
45
47
  export class TabBarToolbar extends ReactWidget {
46
48
 
47
49
  protected current: Widget | undefined;
48
- protected inline = new Map<string, TabBarToolbarItem | ReactTabBarToolbarItem>();
50
+ protected inline = new Map<string, TabBarToolbarItem>();
49
51
  protected more = new Map<string, TabBarToolbarItem>();
50
52
 
51
53
  protected contextKeyListener: Disposable | undefined;
@@ -56,7 +58,6 @@ export class TabBarToolbar extends ReactWidget {
56
58
  @inject(CommandRegistry) protected readonly commands: CommandRegistry;
57
59
  @inject(LabelParser) protected readonly labelParser: LabelParser;
58
60
  @inject(MenuModelRegistry) protected readonly menus: MenuModelRegistry;
59
- @inject(MenuCommandExecutor) protected readonly menuCommandExecutor: MenuCommandExecutor;
60
61
  @inject(ContextMenuRenderer) protected readonly contextMenuRenderer: ContextMenuRenderer;
61
62
  @inject(TabBarToolbarRegistry) protected readonly toolbarRegistry: TabBarToolbarRegistry;
62
63
  @inject(ContextKeyService) protected readonly contextKeyService: ContextKeyService;
@@ -79,34 +80,25 @@ export class TabBarToolbar extends ReactWidget {
79
80
  }));
80
81
  }
81
82
 
82
- updateItems(items: Array<TabBarToolbarItem | ReactTabBarToolbarItem>, current: Widget | undefined): void {
83
+ updateItems(items: Array<TabBarToolbarItem>, current: Widget | undefined): void {
83
84
  this.toDisposeOnUpdateItems.dispose();
84
85
  this.toDisposeOnUpdateItems = new DisposableCollection();
85
86
  this.inline.clear();
86
87
  this.more.clear();
87
88
 
88
- const contextKeys = new Set<string>();
89
- for (const item of items.sort(TabBarToolbarItem.PRIORITY_COMPARATOR).reverse()) {
90
- if (item.command) {
91
- this.commands.getAllHandlers(item.command).forEach(handler => {
92
- if (handler.onDidChangeEnabled) {
93
- this.toDisposeOnUpdateItems.push(handler.onDidChangeEnabled(() => this.maybeUpdate()));
94
- }
95
- });
96
- }
97
- if ('render' in item || item.group === undefined || item.group === 'navigation') {
89
+ for (const item of items.sort(TabBarToolbarAction.PRIORITY_COMPARATOR).reverse()) {
90
+
91
+ if (!('toMenuNode' in item) || item.group === undefined || item.group === 'navigation') {
98
92
  this.inline.set(item.id, item);
99
93
  } else {
100
94
  this.more.set(item.id, item);
101
95
  }
102
96
 
103
- if (item.when) {
104
- this.contextKeyService.parseKeys(item.when)?.forEach(key => contextKeys.add(key));
97
+ if (item.onDidChange) {
98
+ this.toDisposeOnUpdateItems.push(item.onDidChange(() => this.maybeUpdate()));
105
99
  }
106
100
  }
107
101
 
108
- this.updateContextKeyListener(contextKeys);
109
-
110
102
  this.setCurrent(current);
111
103
  if (items.length) {
112
104
  this.show();
@@ -139,124 +131,14 @@ export class TabBarToolbar extends ReactWidget {
139
131
  }
140
132
  }
141
133
 
142
- protected updateContextKeyListener(contextKeys: Set<string>): void {
143
- this.contextKeyListener?.dispose();
144
- if (contextKeys.size > 0) {
145
- this.contextKeyListener = this.contextKeyService.onDidChange(event => {
146
- if (event.affects(contextKeys)) {
147
- this.maybeUpdate();
148
- }
149
- });
150
- }
151
- }
152
-
153
134
  protected render(): React.ReactNode {
154
135
  this.keybindingContextKeys.clear();
155
136
  return <React.Fragment>
156
137
  {this.renderMore()}
157
- {[...this.inline.values()].map(item => {
158
- if (ReactTabBarToolbarItem.is(item)) {
159
- return item.render(this.current);
160
- } else {
161
- return (item.menuPath && this.toolbarRegistry.isNonEmptyMenu(item, this.current) ? this.renderMenuItem(item) : this.renderItem(item));
162
- }
163
- })}
138
+ {[...this.inline.values()].map(item => item.render(this.current))}
164
139
  </React.Fragment>;
165
140
  }
166
141
 
167
- protected resolveKeybindingForCommand(command: string | undefined): string {
168
- let result = '';
169
- if (command) {
170
- const bindings = this.keybindings.getKeybindingsForCommand(command);
171
- let found = false;
172
- if (bindings && bindings.length > 0) {
173
- bindings.forEach(binding => {
174
- if (binding.when) {
175
- this.contextKeyService.parseKeys(binding.when)?.forEach(key => this.keybindingContextKeys.add(key));
176
- }
177
- if (!found && this.keybindings.isEnabledInScope(binding, this.current?.node)) {
178
- found = true;
179
- result = ` (${this.keybindings.acceleratorFor(binding, '+')})`;
180
- }
181
- });
182
- }
183
- }
184
- return result;
185
- }
186
-
187
- protected renderItem(item: RenderedToolbarItem): React.ReactNode {
188
- let innerText = '';
189
- const classNames = [];
190
- const command = item.command ? this.commands.getCommand(item.command) : undefined;
191
- // Fall back to the item ID in extremis so there is _something_ to render in the
192
- // case that there is neither an icon nor a title
193
- const itemText = item.text || command?.label || command?.id || item.id;
194
- if (itemText) {
195
- for (const labelPart of this.labelParser.parse(itemText)) {
196
- if (LabelIcon.is(labelPart)) {
197
- const className = `fa fa-${labelPart.name}${labelPart.animation ? ' fa-' + labelPart.animation : ''}`;
198
- classNames.push(...className.split(' '));
199
- } else {
200
- innerText = labelPart;
201
- }
202
- }
203
- }
204
- const iconClass = (typeof item.icon === 'function' && item.icon()) || item.icon as string || (command && command.iconClass);
205
- if (iconClass) {
206
- classNames.push(iconClass);
207
- }
208
- const tooltipText = item.tooltip || (command && command.label) || '';
209
- const tooltip = `${this.labelParser.stripIcons(tooltipText)}${this.resolveKeybindingForCommand(command?.id)}`;
210
-
211
- // Only present text if there is no icon
212
- if (classNames.length) {
213
- innerText = '';
214
- } else if (innerText) {
215
- // Make room for the label text
216
- classNames.push(NO_ICON_CLASS);
217
- }
218
-
219
- // In any case, this is an action item, with or without icon.
220
- classNames.push(ACTION_ITEM);
221
-
222
- const toolbarItemClassNames = this.getToolbarItemClassNames(item);
223
- return <div key={item.id}
224
- className={toolbarItemClassNames.join(' ')}
225
- onMouseDown={this.onMouseDownEvent}
226
- onMouseUp={this.onMouseUpEvent}
227
- onMouseOut={this.onMouseUpEvent} >
228
- <div id={item.id} className={classNames.join(' ')}
229
- onClick={e => this.executeCommand(e, item)}
230
- title={tooltip}>{innerText}
231
- </div>
232
- </div>;
233
- }
234
-
235
- protected isEnabled(item: TabBarToolbarItem): boolean {
236
- if (!!item.command) {
237
- return this.commandIsEnabled(item.command) && this.evaluateWhenClause(item.when);
238
- } else {
239
- return !!item.menuPath;
240
- }
241
- }
242
-
243
- protected getToolbarItemClassNames(item: TabBarToolbarItem): string[] {
244
- const classNames = [TabBarToolbar.Styles.TAB_BAR_TOOLBAR_ITEM];
245
- if (item.command) {
246
- if (this.isEnabled(item)) {
247
- classNames.push('enabled');
248
- }
249
- if (this.commandIsToggled(item.command)) {
250
- classNames.push('toggled');
251
- }
252
- } else {
253
- if (this.isEnabled(item)) {
254
- classNames.push('enabled');
255
- }
256
- }
257
- return classNames;
258
- }
259
-
260
142
  protected renderMore(): React.ReactNode {
261
143
  return !!this.more.size && <div key='__more__' className={TabBarToolbar.Styles.TAB_BAR_TOOLBAR_ITEM + ' enabled'}>
262
144
  <div id='__more__' className={codicon('ellipsis', true)} onClick={this.showMoreContextMenu}
@@ -267,116 +149,35 @@ export class TabBarToolbar extends ReactWidget {
267
149
  protected showMoreContextMenu = (event: React.MouseEvent) => {
268
150
  event.stopPropagation();
269
151
  event.preventDefault();
270
- const anchor = this.toAnchor(event);
152
+ const anchor = toAnchor(event);
271
153
  this.renderMoreContextMenu(anchor);
272
154
  };
273
155
 
274
- protected toAnchor(event: React.MouseEvent): Anchor {
275
- const itemBox = event.currentTarget.closest('.' + TabBarToolbar.Styles.TAB_BAR_TOOLBAR_ITEM)?.getBoundingClientRect();
276
- return itemBox ? { y: itemBox.bottom, x: itemBox.left } : event.nativeEvent;
277
- }
278
-
279
- renderMoreContextMenu(anchor: Anchor, subpath?: MenuPath): ContextMenuAccess {
156
+ renderMoreContextMenu(anchor: Anchor): ContextMenuAccess {
280
157
  const toDisposeOnHide = new DisposableCollection();
281
158
  this.addClass('menu-open');
282
159
  toDisposeOnHide.push(Disposable.create(() => this.removeClass('menu-open')));
283
- if (subpath) {
284
- toDisposeOnHide.push(this.menus.linkSubmenu(TAB_BAR_TOOLBAR_CONTEXT_MENU, subpath));
285
- } else {
286
- for (const item of this.more.values()) {
287
- if (item.menuPath && !item.command) {
288
- toDisposeOnHide.push(this.menus.linkSubmenu(TAB_BAR_TOOLBAR_CONTEXT_MENU, item.menuPath, undefined, item.group));
289
- } else if (item.command) {
290
- // Register a submenu for the item, if the group is in format `<submenu group>/<submenu name>/.../<item group>`
291
- if (item.group?.includes('/')) {
292
- const split = item.group.split('/');
293
- const paths: string[] = [];
294
- for (let i = 0; i < split.length - 1; i += 2) {
295
- paths.push(split[i], split[i + 1]);
296
- toDisposeOnHide.push(this.menus.registerSubmenu([...TAB_BAR_TOOLBAR_CONTEXT_MENU, ...paths], split[i + 1], { order: item.order }));
297
- }
160
+
161
+ const menu = new GroupImpl('contextMenu');
162
+ for (const item of this.more.values()) {
163
+ if (item.toMenuNode) {
164
+ const node = item.toMenuNode();
165
+ if (node) {
166
+ if (item.group) {
167
+ menu.getOrCreate([item.group], 0, 1).addNode(node);
168
+ } else {
169
+ menu.addNode(node);
298
170
  }
299
- toDisposeOnHide.push(this.menus.registerMenuAction([...TAB_BAR_TOOLBAR_CONTEXT_MENU, ...item.group!.split('/')], {
300
- label: (item as RenderedToolbarItem).tooltip,
301
- commandId: item.command,
302
- when: item.when,
303
- order: item.order
304
- }));
305
171
  }
306
172
  }
307
173
  }
308
174
  return this.contextMenuRenderer.render({
309
- menuPath: TAB_BAR_TOOLBAR_CONTEXT_MENU,
310
- args: [this.current],
311
- anchor,
312
- context: this.current?.node || this.node,
313
- onHide: () => toDisposeOnHide.dispose(),
314
- skipSingleRootNode: true,
315
- });
316
- }
317
-
318
- /**
319
- * Renders a toolbar item that is a menu, presenting it as a button with a little
320
- * chevron decoration that pops up a floating menu when clicked.
321
- *
322
- * @param item a toolbar item that is a menu item
323
- * @returns the rendered toolbar item
324
- */
325
- protected renderMenuItem(item: RenderedToolbarItem): React.ReactNode {
326
- const command = item.command ? this.commands.getCommand(item.command) : undefined;
327
- const icon = (typeof item.icon === 'function' && item.icon()) || item.icon as string || (command && command.iconClass) || 'ellipsis';
328
-
329
- let contextMatcher: ContextMatcher = this.contextKeyService;
330
- if (item.contextKeyOverlays) {
331
- contextMatcher = this.contextKeyService.createOverlay(Object.keys(item.contextKeyOverlays).map(key => [key, item.contextKeyOverlays![key]]));
332
- }
333
-
334
- return <div key={item.id}
335
- className={TabBarToolbar.Styles.TAB_BAR_TOOLBAR_ITEM + ' enabled menu'}
336
- >
337
- <div className={codicon(icon, true)}
338
- title={item.text}
339
- onClick={e => this.executeCommand(e, item)}
340
- />
341
- <div className={ACTION_ITEM} onClick={event => this.showPopupMenu(item.menuPath!, event, contextMatcher)}>
342
- <div className={codicon('chevron-down') + ' chevron'} />
343
- </div>
344
-
345
- </div >;
346
- }
347
-
348
- /**
349
- * Presents the menu to popup on the `event` that is the clicking of
350
- * a menu toolbar item.
351
- *
352
- * @param menuPath the path of the registered menu to show
353
- * @param event the mouse event triggering the menu
354
- */
355
- protected showPopupMenu = (menuPath: MenuPath, event: React.MouseEvent, contextMatcher: ContextMatcher) => {
356
- event.stopPropagation();
357
- event.preventDefault();
358
- const anchor = this.toAnchor(event);
359
- this.renderPopupMenu(menuPath, anchor, contextMatcher);
360
- };
361
-
362
- /**
363
- * Renders the menu popped up on a menu toolbar item.
364
- *
365
- * @param menuPath the path of the registered menu to render
366
- * @param anchor a description of where to render the menu
367
- * @returns platform-specific access to the rendered context menu
368
- */
369
- protected renderPopupMenu(menuPath: MenuPath, anchor: Anchor, contextMatcher: ContextMatcher): ContextMenuAccess {
370
- const toDisposeOnHide = new DisposableCollection();
371
- this.addClass('menu-open');
372
- toDisposeOnHide.push(Disposable.create(() => this.removeClass('menu-open')));
373
-
374
- return this.contextMenuRenderer.render({
375
- menuPath,
175
+ menu: MenuModelRegistry.removeSingleRootNodes(menu),
176
+ menuPath: ['contextMenu'],
376
177
  args: [this.current],
377
178
  anchor,
378
179
  context: this.current?.node || this.node,
379
- contextKeyService: contextMatcher,
180
+ contextKeyService: this.contextKeyService,
380
181
  onHide: () => toDisposeOnHide.dispose()
381
182
  });
382
183
  }
@@ -397,39 +198,11 @@ export class TabBarToolbar extends ReactWidget {
397
198
  return whenClause ? this.contextKeyService.match(whenClause, this.current?.node) : true;
398
199
  }
399
200
 
400
- protected executeCommand(e: React.MouseEvent<HTMLElement>, item: TabBarToolbarItem): void {
401
- e.preventDefault();
402
- e.stopPropagation();
403
-
404
- if (!item || !this.isEnabled(item)) {
405
- return;
406
- }
407
-
408
- if (item.command && item.delegateMenuPath) {
409
- this.menuCommandExecutor.executeCommand(item.delegateMenuPath, item.command, this.current);
410
- } else if (item.command) {
411
- this.commands.executeCommand(item.command, this.current);
412
- } else if (item.menuPath) {
413
- this.renderMoreContextMenu(this.toAnchor(e), item.menuPath);
414
- }
415
- this.maybeUpdate();
416
- };
417
-
418
201
  protected maybeUpdate(): void {
419
202
  if (!this.isDisposed) {
420
203
  this.update();
421
204
  }
422
205
  }
423
-
424
- protected onMouseDownEvent = (e: React.MouseEvent<HTMLElement>) => {
425
- if (e.button === 0) {
426
- e.currentTarget.classList.add('active');
427
- }
428
- };
429
-
430
- protected onMouseUpEvent = (e: React.MouseEvent<HTMLElement>) => {
431
- e.currentTarget.classList.remove('active');
432
- };
433
206
  }
434
207
 
435
208
  export namespace TabBarToolbar {
@@ -0,0 +1,251 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2024 STMicroelectronics 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-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ import { ContextKeyService } from '../../context-key-service';
18
+ import { ReactTabBarToolbarAction, RenderedToolbarAction, TabBarToolbarActionBase } from './tab-bar-toolbar-types';
19
+ import { Widget } from '@lumino/widgets';
20
+ import { LabelIcon, LabelParser } from '../../label-parser';
21
+ import { CommandRegistry, Event, Disposable, Emitter, DisposableCollection } from '../../../common';
22
+ import { KeybindingRegistry } from '../../keybinding';
23
+ import { ACTION_ITEM } from '../../widgets';
24
+ import { TabBarToolbar } from './tab-bar-toolbar';
25
+ import * as React from 'react';
26
+ import { ActionMenuNode, GroupImpl, MenuNode } from '../../../common/menu';
27
+
28
+ export interface TabBarToolbarItem {
29
+ id: string;
30
+ isVisible(widget: Widget): boolean;
31
+ isEnabled(widget?: Widget): boolean;
32
+ isToggled(): boolean;
33
+ render(widget?: Widget): React.ReactNode;
34
+ onDidChange?: Event<void>;
35
+ group?: string;
36
+ priority?: number;
37
+ toMenuNode?(): MenuNode;
38
+ }
39
+
40
+ /**
41
+ * Class name indicating rendering of a toolbar item without an icon but instead with a text label.
42
+ */
43
+ const NO_ICON_CLASS = 'no-icon';
44
+
45
+ class AbstractToolbarItemImpl<T extends TabBarToolbarActionBase> {
46
+ constructor(
47
+ protected readonly commandRegistry: CommandRegistry,
48
+ protected readonly contextKeyService: ContextKeyService,
49
+ protected readonly action: T) {
50
+ }
51
+
52
+ get id(): string {
53
+ return this.action.id;
54
+ }
55
+ get group(): string | undefined {
56
+ return this.action.group;
57
+ }
58
+ get priority(): number | undefined {
59
+ return this.action.priority;
60
+ }
61
+
62
+ get onDidChange(): Event<void> | undefined {
63
+ return this.action.onDidChange;
64
+ }
65
+
66
+ isVisible(widget: Widget): boolean {
67
+ if (this.action.isVisible) {
68
+ return this.action.isVisible(widget);
69
+ }
70
+ const actionVisible = !this.action.command || this.commandRegistry.isVisible(this.action.command, widget);
71
+ const contextMatches = !this.action.when || this.contextKeyService.match(this.action.when);
72
+
73
+ return actionVisible && contextMatches;
74
+ }
75
+
76
+ isEnabled(widget?: Widget): boolean {
77
+ return this.action.command ? this.commandRegistry.isEnabled(this.action.command, widget) : !!this.action.menuPath;
78
+ }
79
+ isToggled(): boolean {
80
+ return this.action.command ? this.commandRegistry.isToggled(this.action.command) : true;
81
+ }
82
+ }
83
+
84
+ export class RenderedToolbarItemImpl extends AbstractToolbarItemImpl<RenderedToolbarAction> implements TabBarToolbarItem {
85
+ protected contextKeyListener: Disposable | undefined;
86
+ protected disposables = new DisposableCollection();
87
+
88
+ constructor(
89
+ commandRegistry: CommandRegistry,
90
+ contextKeyService: ContextKeyService,
91
+ protected readonly keybindingRegistry: KeybindingRegistry,
92
+ protected readonly labelParser: LabelParser,
93
+ action: RenderedToolbarAction) {
94
+ super(commandRegistry, contextKeyService, action);
95
+ if (action.onDidChange) {
96
+ this.disposables.push(action.onDidChange(() => this.onDidChangeEmitter.fire()));
97
+ }
98
+ }
99
+
100
+ dispose(): void {
101
+ this.disposables.dispose();
102
+ }
103
+
104
+ updateContextKeyListener(when: string): void {
105
+ const contextKeys = new Set<string>();
106
+ this.contextKeyService.parseKeys(when)?.forEach(key => contextKeys.add(key));
107
+ if (contextKeys.size > 0) {
108
+ this.contextKeyListener = this.contextKeyService.onDidChange(change => {
109
+ if (change.affects(contextKeys)) {
110
+ this.onDidChangeEmitter.fire();
111
+ }
112
+ });
113
+ }
114
+ }
115
+
116
+ render(widget?: Widget | undefined): React.ReactNode {
117
+ return this.renderItem(widget);
118
+ }
119
+
120
+ protected getToolbarItemClassNames(widget?: Widget): string[] {
121
+ const classNames = [TabBarToolbar.Styles.TAB_BAR_TOOLBAR_ITEM];
122
+ if (this.isEnabled(widget)) {
123
+ classNames.push('enabled');
124
+ }
125
+ if (this.isToggled()) {
126
+ classNames.push('toggled');
127
+ }
128
+ return classNames;
129
+ }
130
+
131
+ protected resolveKeybindingForCommand(widget: Widget | undefined, command: string | undefined): string {
132
+ let result = '';
133
+ if (this.action.command) {
134
+ const bindings = this.keybindingRegistry.getKeybindingsForCommand(this.action.command);
135
+ let found = false;
136
+ if (bindings && bindings.length > 0) {
137
+ bindings.forEach(binding => {
138
+ if (binding.when) {
139
+ this.updateContextKeyListener(binding.when);
140
+ }
141
+ if (!found && this.keybindingRegistry.isEnabledInScope(binding, widget?.node)) {
142
+ found = true;
143
+ result = ` (${this.keybindingRegistry.acceleratorFor(binding, '+')})`;
144
+ }
145
+ });
146
+ }
147
+ }
148
+ return result;
149
+ }
150
+
151
+ protected readonly onDidChangeEmitter = new Emitter<void>;
152
+ override get onDidChange(): Event<void> | undefined {
153
+ return this.onDidChangeEmitter.event;
154
+ }
155
+
156
+ toMenuNode?(): MenuNode {
157
+ const action = new ActionMenuNode({
158
+ label: this.action.tooltip,
159
+ commandId: this.action.command!,
160
+ when: this.action.when,
161
+ order: this.action.order
162
+ }, this.commandRegistry, this.keybindingRegistry, this.contextKeyService);
163
+
164
+ // Register a submenu for the item, if the group is in format `<submenu group>/<submenu name>/.../<item group>`
165
+ const menuPath = this.action.group?.split('/') || [];
166
+ if (menuPath.length > 1) {
167
+ let menu = new GroupImpl(menuPath[0], this.action.order);
168
+ menu = menu.getOrCreate(menuPath, 1, menuPath.length);
169
+ menu.addNode(action);
170
+ return menu;
171
+ }
172
+ return action;
173
+ }
174
+
175
+ protected onMouseDownEvent = (e: React.MouseEvent<HTMLElement>) => {
176
+ if (e.button === 0) {
177
+ e.currentTarget.classList.add('active');
178
+ }
179
+ };
180
+
181
+ protected onMouseUpEvent = (e: React.MouseEvent<HTMLElement>) => {
182
+ e.currentTarget.classList.remove('active');
183
+ };
184
+
185
+ protected executeCommand(e: React.MouseEvent<HTMLElement>, widget?: Widget): void {
186
+ e.preventDefault();
187
+ e.stopPropagation();
188
+
189
+ if (!this.isEnabled(widget)) {
190
+ return;
191
+ }
192
+
193
+ if (this.action.command) {
194
+ this.commandRegistry.executeCommand(this.action.command, widget);
195
+ }
196
+ };
197
+
198
+ protected renderItem(widget?: Widget): React.ReactNode {
199
+ let innerText = '';
200
+ const classNames = [];
201
+ const command = this.action.command ? this.commandRegistry.getCommand(this.action.command) : undefined;
202
+ // Fall back to the item ID in extremis so there is _something_ to render in the
203
+ // case that there is neither an icon nor a title
204
+ const itemText = this.action.text || command?.label || command?.id || this.action.id;
205
+ if (itemText) {
206
+ for (const labelPart of this.labelParser.parse(itemText)) {
207
+ if (LabelIcon.is(labelPart)) {
208
+ const className = `fa fa-${labelPart.name}${labelPart.animation ? ' fa-' + labelPart.animation : ''}`;
209
+ classNames.push(...className.split(' '));
210
+ } else {
211
+ innerText = labelPart;
212
+ }
213
+ }
214
+ }
215
+ const iconClass = (typeof this.action.icon === 'function' && this.action.icon()) || this.action.icon as string || (command && command.iconClass);
216
+ if (iconClass) {
217
+ classNames.push(iconClass);
218
+ }
219
+ const tooltipText = this.action.tooltip || (command && command.label) || '';
220
+ const tooltip = `${this.labelParser.stripIcons(tooltipText)}${this.resolveKeybindingForCommand(widget, command?.id)}`;
221
+
222
+ // Only present text if there is no icon
223
+ if (classNames.length) {
224
+ innerText = '';
225
+ } else if (innerText) {
226
+ // Make room for the label text
227
+ classNames.push(NO_ICON_CLASS);
228
+ }
229
+
230
+ // In any case, this is an action item, with or without icon.
231
+ classNames.push(ACTION_ITEM);
232
+
233
+ const toolbarItemClassNames = this.getToolbarItemClassNames(widget);
234
+ return <div key={this.action.id}
235
+ className={toolbarItemClassNames.join(' ')}
236
+ onMouseDown={this.onMouseDownEvent}
237
+ onMouseUp={this.onMouseUpEvent}
238
+ onMouseOut={this.onMouseUpEvent} >
239
+ <div id={this.action.id} className={classNames.join(' ')}
240
+ onClick={e => this.executeCommand(e, widget)}
241
+ title={tooltip} > {innerText}
242
+ </div>
243
+ </div>;
244
+ }
245
+ }
246
+
247
+ export class ReactToolbarItemImpl extends AbstractToolbarItemImpl<ReactTabBarToolbarAction> implements TabBarToolbarItem {
248
+ render(widget?: Widget | undefined): React.ReactNode {
249
+ return this.action.render(widget);
250
+ }
251
+ }
@@ -958,6 +958,7 @@ export class ToolbarAwareTabBar extends ScrollableTabBar {
958
958
  this.node.appendChild(this.breadcrumbsContainer);
959
959
 
960
960
  this.toolbar = this.tabBarToolbarFactory();
961
+ this.toDispose.push(this.toolbar);
961
962
  this.toDispose.push(this.tabBarToolbarRegistry.onDidChange(() => this.update()));
962
963
  this.toDispose.push(this.breadcrumbsRenderer);
963
964
 
@@ -1009,7 +1010,7 @@ export class ToolbarAwareTabBar extends ScrollableTabBar {
1009
1010
 
1010
1011
  protected override onBeforeDetach(msg: Message): void {
1011
1012
  if (this.toolbar && this.toolbar.isAttached) {
1012
- this.toolbar.dispose();
1013
+ Widget.detach(this.toolbar);
1013
1014
  }
1014
1015
  super.onBeforeDetach(msg);
1015
1016
  }