@theia/core 1.71.0-next.6 → 1.71.0-next.64
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.
- package/README.md +13 -13
- package/i18n/nls.cs.json +4 -4
- package/i18n/nls.de.json +4 -4
- package/i18n/nls.es.json +4 -4
- package/i18n/nls.fr.json +4 -4
- package/i18n/nls.hu.json +4 -4
- package/i18n/nls.it.json +4 -4
- package/i18n/nls.ja.json +4 -4
- package/i18n/nls.ko.json +4 -4
- package/i18n/nls.pl.json +4 -4
- package/i18n/nls.pt-br.json +4 -4
- package/i18n/nls.ru.json +4 -4
- package/i18n/nls.tr.json +4 -4
- package/i18n/nls.zh-cn.json +4 -4
- package/i18n/nls.zh-tw.json +4 -4
- package/lib/browser/catalog.json +149 -8
- package/lib/browser/common-frontend-contribution.js +2 -2
- package/lib/browser/common-frontend-contribution.js.map +1 -1
- package/lib/browser/components/card.d.ts.map +1 -1
- package/lib/browser/components/card.js +11 -3
- package/lib/browser/components/card.js.map +1 -1
- package/lib/browser/connection-status-service.js +1 -1
- package/lib/browser/connection-status-service.js.map +1 -1
- package/lib/browser/keyboard/index.d.ts +1 -0
- package/lib/browser/keyboard/index.d.ts.map +1 -1
- package/lib/browser/keyboard/index.js +1 -0
- package/lib/browser/keyboard/index.js.map +1 -1
- package/lib/browser/keyboard/keyboard-utils.d.ts +17 -0
- package/lib/browser/keyboard/keyboard-utils.d.ts.map +1 -0
- package/lib/browser/keyboard/keyboard-utils.js +40 -0
- package/lib/browser/keyboard/keyboard-utils.js.map +1 -0
- package/lib/browser/menu/browser-menu-plugin.d.ts.map +1 -1
- package/lib/browser/menu/browser-menu-plugin.js +8 -1
- package/lib/browser/menu/browser-menu-plugin.js.map +1 -1
- package/lib/browser/messaging/messaging-frontend-module.d.ts.map +1 -1
- package/lib/browser/messaging/messaging-frontend-module.js +3 -0
- package/lib/browser/messaging/messaging-frontend-module.js.map +1 -1
- package/lib/browser/messaging/ws-connection-source.d.ts +2 -1
- package/lib/browser/messaging/ws-connection-source.d.ts.map +1 -1
- package/lib/browser/messaging/ws-connection-source.js +5 -2
- package/lib/browser/messaging/ws-connection-source.js.map +1 -1
- package/lib/browser/saveable-service.d.ts +9 -2
- package/lib/browser/saveable-service.d.ts.map +1 -1
- package/lib/browser/saveable-service.js +34 -25
- package/lib/browser/saveable-service.js.map +1 -1
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.d.ts +1 -0
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.d.ts.map +1 -1
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.js +10 -1
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.js.map +1 -1
- package/lib/browser/shell/tab-bar-toolbar/tab-toolbar-item.d.ts +2 -0
- package/lib/browser/shell/tab-bar-toolbar/tab-toolbar-item.d.ts.map +1 -1
- package/lib/browser/shell/tab-bar-toolbar/tab-toolbar-item.js +11 -2
- package/lib/browser/shell/tab-bar-toolbar/tab-toolbar-item.js.map +1 -1
- package/lib/browser/window/browser-window-module.d.ts.map +1 -1
- package/lib/browser/window/browser-window-module.js +2 -0
- package/lib/browser/window/browser-window-module.js.map +1 -1
- package/lib/browser/window/default-secondary-window-service.d.ts +2 -0
- package/lib/browser/window/default-secondary-window-service.d.ts.map +1 -1
- package/lib/browser/window/default-secondary-window-service.js +7 -0
- package/lib/browser/window/default-secondary-window-service.js.map +1 -1
- package/lib/browser/window/window-focus-service.d.ts +71 -0
- package/lib/browser/window/window-focus-service.d.ts.map +1 -0
- package/lib/browser/window/window-focus-service.js +173 -0
- package/lib/browser/window/window-focus-service.js.map +1 -0
- package/lib/common/event.d.ts +16 -0
- package/lib/common/event.d.ts.map +1 -1
- package/lib/common/event.js +20 -2
- package/lib/common/event.js.map +1 -1
- package/lib/common/event.spec.js +63 -0
- package/lib/common/event.spec.js.map +1 -1
- package/lib/common/glob.d.ts +2 -0
- package/lib/common/glob.d.ts.map +1 -1
- package/lib/common/glob.js +8 -7
- package/lib/common/glob.js.map +1 -1
- package/lib/common/message-rpc/channel.d.ts +1 -1
- package/lib/common/message-rpc/channel.d.ts.map +1 -1
- package/lib/common/message-rpc/channel.js +20 -12
- package/lib/common/message-rpc/channel.js.map +1 -1
- package/lib/common/message-rpc/channel.spec.d.ts.map +1 -1
- package/lib/common/message-rpc/channel.spec.js +94 -0
- package/lib/common/message-rpc/channel.spec.js.map +1 -1
- package/lib/common/message-rpc/rpc-protocol.d.ts.map +1 -1
- package/lib/common/message-rpc/rpc-protocol.js +13 -3
- package/lib/common/message-rpc/rpc-protocol.js.map +1 -1
- package/lib/common/message-rpc/uint8-array-message-buffer.d.ts.map +1 -1
- package/lib/common/message-rpc/uint8-array-message-buffer.js +1 -1
- package/lib/common/message-rpc/uint8-array-message-buffer.js.map +1 -1
- package/lib/common/messaging/index.d.ts +1 -0
- package/lib/common/messaging/index.d.ts.map +1 -1
- package/lib/common/messaging/index.js +1 -0
- package/lib/common/messaging/index.js.map +1 -1
- package/lib/common/messaging/socket-write-buffer.d.ts +4 -3
- package/lib/common/messaging/socket-write-buffer.d.ts.map +1 -1
- package/lib/common/messaging/socket-write-buffer.js +14 -4
- package/lib/common/messaging/socket-write-buffer.js.map +1 -1
- package/lib/common/preferences/index.d.ts +1 -0
- package/lib/common/preferences/index.d.ts.map +1 -1
- package/lib/common/preferences/index.js +1 -0
- package/lib/common/preferences/index.js.map +1 -1
- package/lib/common/preferences/preference-utils.d.ts +6 -0
- package/lib/common/preferences/preference-utils.d.ts.map +1 -0
- package/lib/common/preferences/preference-utils.js +29 -0
- package/lib/common/preferences/preference-utils.js.map +1 -0
- package/lib/common/resource.d.ts +2 -0
- package/lib/common/resource.d.ts.map +1 -1
- package/lib/common/resource.js +7 -3
- package/lib/common/resource.js.map +1 -1
- package/lib/electron-browser/menu/electron-main-menu-factory.d.ts.map +1 -1
- package/lib/electron-browser/menu/electron-main-menu-factory.js +5 -1
- package/lib/electron-browser/menu/electron-main-menu-factory.js.map +1 -1
- package/lib/electron-browser/messaging/electron-messaging-frontend-module.d.ts.map +1 -1
- package/lib/electron-browser/messaging/electron-messaging-frontend-module.js +3 -0
- package/lib/electron-browser/messaging/electron-messaging-frontend-module.js.map +1 -1
- package/lib/electron-browser/window/electron-window-module.d.ts.map +1 -1
- package/lib/electron-browser/window/electron-window-module.js +2 -0
- package/lib/electron-browser/window/electron-window-module.js.map +1 -1
- package/lib/electron-main/electron-api-main.d.ts.map +1 -1
- package/lib/electron-main/electron-api-main.js +4 -2
- package/lib/electron-main/electron-api-main.js.map +1 -1
- package/lib/electron-main/theia-electron-window.d.ts.map +1 -1
- package/lib/electron-main/theia-electron-window.js +3 -0
- package/lib/electron-main/theia-electron-window.js.map +1 -1
- package/lib/node/messaging/default-messaging-service.d.ts.map +1 -1
- package/lib/node/messaging/default-messaging-service.js +1 -0
- package/lib/node/messaging/default-messaging-service.js.map +1 -1
- package/lib/node/messaging/index.d.ts +1 -0
- package/lib/node/messaging/index.d.ts.map +1 -1
- package/lib/node/messaging/index.js +1 -0
- package/lib/node/messaging/index.js.map +1 -1
- package/lib/node/messaging/messaging-backend-module.d.ts.map +1 -1
- package/lib/node/messaging/messaging-backend-module.js +4 -0
- package/lib/node/messaging/messaging-backend-module.js.map +1 -1
- package/lib/node/messaging/test/default-messaging-service.spec.d.ts +2 -0
- package/lib/node/messaging/test/default-messaging-service.spec.d.ts.map +1 -0
- package/lib/node/messaging/test/default-messaging-service.spec.js +81 -0
- package/lib/node/messaging/test/default-messaging-service.spec.js.map +1 -0
- package/lib/node/messaging/websocket-frontend-connection-service.d.ts +9 -5
- package/lib/node/messaging/websocket-frontend-connection-service.d.ts.map +1 -1
- package/lib/node/messaging/websocket-frontend-connection-service.js +21 -5
- package/lib/node/messaging/websocket-frontend-connection-service.js.map +1 -1
- package/lib/node/process-utils.d.ts.map +1 -1
- package/lib/node/process-utils.js +9 -1
- package/lib/node/process-utils.js.map +1 -1
- package/package.json +32 -32
- package/src/browser/common-frontend-contribution.ts +2 -2
- package/src/browser/components/card.tsx +13 -2
- package/src/browser/connection-status-service.ts +1 -1
- package/src/browser/keyboard/index.ts +1 -0
- package/src/browser/keyboard/keyboard-utils.ts +37 -0
- package/src/browser/menu/browser-menu-plugin.ts +8 -1
- package/src/browser/messaging/messaging-frontend-module.ts +3 -0
- package/src/browser/messaging/ws-connection-source.ts +3 -2
- package/src/browser/saveable-service.ts +34 -27
- package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar.tsx +14 -1
- package/src/browser/shell/tab-bar-toolbar/tab-toolbar-item.tsx +13 -2
- package/src/browser/style/card.css +4 -2
- package/src/browser/style/hover-service.css +7 -0
- package/src/browser/window/browser-window-module.ts +2 -0
- package/src/browser/window/default-secondary-window-service.ts +6 -0
- package/src/browser/window/window-focus-service.ts +187 -0
- package/src/common/event.spec.ts +80 -0
- package/src/common/event.ts +31 -2
- package/src/common/glob.ts +2 -2
- package/src/common/i18n/nls.metadata.json +4254 -1058
- package/src/common/message-rpc/channel.spec.ts +116 -0
- package/src/common/message-rpc/channel.ts +15 -11
- package/src/common/message-rpc/rpc-protocol.ts +12 -3
- package/src/common/message-rpc/uint8-array-message-buffer.ts +1 -1
- package/src/common/messaging/index.ts +1 -0
- package/src/common/messaging/socket-write-buffer.ts +10 -4
- package/src/common/preferences/index.ts +1 -0
- package/src/common/preferences/preference-utils.ts +28 -0
- package/src/common/resource.ts +8 -2
- package/src/electron-browser/menu/electron-main-menu-factory.ts +5 -1
- package/src/electron-browser/messaging/electron-messaging-frontend-module.ts +3 -0
- package/src/electron-browser/window/electron-window-module.ts +2 -0
- package/src/electron-main/electron-api-main.ts +4 -2
- package/src/electron-main/theia-electron-window.ts +3 -0
- package/src/node/messaging/default-messaging-service.ts +1 -0
- package/src/node/messaging/index.ts +1 -0
- package/src/node/messaging/messaging-backend-module.ts +5 -1
- package/src/node/messaging/test/default-messaging-service.spec.ts +85 -0
- package/src/node/messaging/websocket-frontend-connection-service.ts +20 -7
- package/src/node/process-utils.ts +9 -1
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@theia/core",
|
|
3
|
-
"version": "1.71.0-next.
|
|
3
|
+
"version": "1.71.0-next.64+5f7caff6d",
|
|
4
4
|
"description": "Theia is a cloud & desktop IDE framework implemented in TypeScript.",
|
|
5
5
|
"main": "lib/common/index.js",
|
|
6
6
|
"typings": "lib/common/index.d.ts",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@babel/runtime": "^7.
|
|
8
|
+
"@babel/runtime": "^7.29.2",
|
|
9
9
|
"@lumino/algorithm": "^2.0.4",
|
|
10
10
|
"@lumino/commands": "^2.3.3",
|
|
11
11
|
"@lumino/coreutils": "^2.2.2",
|
|
@@ -16,31 +16,31 @@
|
|
|
16
16
|
"@lumino/signaling": "^2.1.5",
|
|
17
17
|
"@lumino/virtualdom": "^2.0.4",
|
|
18
18
|
"@lumino/widgets": "2.7.5",
|
|
19
|
-
"@parcel/watcher": "^2.5.
|
|
20
|
-
"@theia/application-package": "1.71.0-next.
|
|
21
|
-
"@theia/request": "1.71.0-next.
|
|
22
|
-
"@types/body-parser": "^1.
|
|
19
|
+
"@parcel/watcher": "^2.5.6",
|
|
20
|
+
"@theia/application-package": "1.71.0-next.64+5f7caff6d",
|
|
21
|
+
"@theia/request": "1.71.0-next.64+5f7caff6d",
|
|
22
|
+
"@types/body-parser": "^1.19.6",
|
|
23
23
|
"@types/express": "^4.17.21",
|
|
24
24
|
"@types/fs-extra": "^4.0.2",
|
|
25
25
|
"@types/lodash.debounce": "4.0.3",
|
|
26
|
-
"@types/lodash.throttle": "^4.1.
|
|
27
|
-
"@types/markdown-it": "^14.1.
|
|
26
|
+
"@types/lodash.throttle": "^4.1.9",
|
|
27
|
+
"@types/markdown-it": "^14.1.2",
|
|
28
28
|
"@types/markdown-it-emoji": "^3.0.1",
|
|
29
|
-
"@types/react": "^18.
|
|
30
|
-
"@types/react-dom": "^18.
|
|
31
|
-
"@types/route-parser": "^0.1.
|
|
32
|
-
"@types/safer-buffer": "^2.1.
|
|
29
|
+
"@types/react": "^18.3.28",
|
|
30
|
+
"@types/react-dom": "^18.3.7",
|
|
31
|
+
"@types/route-parser": "^0.1.7",
|
|
32
|
+
"@types/safer-buffer": "^2.1.3",
|
|
33
33
|
"@types/uuid": "^9.0.8",
|
|
34
|
-
"@types/ws": "^8.
|
|
34
|
+
"@types/ws": "^8.18.1",
|
|
35
35
|
"@types/yargs": "^15",
|
|
36
36
|
"@vscode/codicons": "0.0.45",
|
|
37
|
-
"ajv": "^6.
|
|
38
|
-
"async-mutex": "^0.4.
|
|
39
|
-
"body-parser": "^1.
|
|
40
|
-
"cookie": "^1.
|
|
41
|
-
"dompurify": "^3.
|
|
37
|
+
"ajv": "^6.14.0",
|
|
38
|
+
"async-mutex": "^0.4.1",
|
|
39
|
+
"body-parser": "^1.20.4",
|
|
40
|
+
"cookie": "^1.1.1",
|
|
41
|
+
"dompurify": "^3.3.3",
|
|
42
42
|
"drivelist": "^12.0.2",
|
|
43
|
-
"express": "^4.
|
|
43
|
+
"express": "^4.22.1",
|
|
44
44
|
"fast-json-stable-stringify": "^2.1.0",
|
|
45
45
|
"file-icons-js": "~1.0.3",
|
|
46
46
|
"font-awesome": "^4.7.0",
|
|
@@ -48,32 +48,32 @@
|
|
|
48
48
|
"fuzzy": "^0.1.3",
|
|
49
49
|
"http-proxy-agent": "^5.0.0",
|
|
50
50
|
"https-proxy-agent": "^5.0.0",
|
|
51
|
-
"iconv-lite": "^0.6.
|
|
52
|
-
"inversify": "^6.
|
|
53
|
-
"jschardet": "^2.
|
|
51
|
+
"iconv-lite": "^0.6.3",
|
|
52
|
+
"inversify": "^6.2.2",
|
|
53
|
+
"jschardet": "^2.3.0",
|
|
54
54
|
"keytar": "7.9.0",
|
|
55
55
|
"lodash.debounce": "^4.0.8",
|
|
56
56
|
"lodash.throttle": "^4.1.1",
|
|
57
|
-
"markdown-it": "^14.1.
|
|
57
|
+
"markdown-it": "^14.1.1",
|
|
58
58
|
"markdown-it-anchor": "^9.2.0",
|
|
59
59
|
"markdown-it-emoji": "^3.0.0",
|
|
60
|
-
"msgpackr": "^1.
|
|
60
|
+
"msgpackr": "^1.11.9",
|
|
61
61
|
"p-debounce": "^2.1.0",
|
|
62
62
|
"perfect-scrollbar": "1.5.5",
|
|
63
|
-
"react": "^18.
|
|
64
|
-
"react-dom": "^18.
|
|
65
|
-
"react-tooltip": "^4.
|
|
66
|
-
"react-virtuoso": "^2.
|
|
63
|
+
"react": "^18.3.1",
|
|
64
|
+
"react-dom": "^18.3.1",
|
|
65
|
+
"react-tooltip": "^4.5.1",
|
|
66
|
+
"react-virtuoso": "^2.19.1",
|
|
67
67
|
"reflect-metadata": "^0.2.2",
|
|
68
68
|
"route-parser": "^0.0.5",
|
|
69
69
|
"safer-buffer": "^2.1.2",
|
|
70
|
-
"socket.io": "^4.
|
|
71
|
-
"socket.io-client": "^4.
|
|
70
|
+
"socket.io": "^4.8.3",
|
|
71
|
+
"socket.io-client": "^4.8.3",
|
|
72
72
|
"tslib": "^2.6.2",
|
|
73
73
|
"uuid": "^9.0.1",
|
|
74
74
|
"vscode-languageserver-protocol": "3.17.5",
|
|
75
75
|
"vscode-uri": "3.0.8",
|
|
76
|
-
"ws": "^8.
|
|
76
|
+
"ws": "^8.20.0",
|
|
77
77
|
"yargs": "^15.3.1"
|
|
78
78
|
},
|
|
79
79
|
"peerDependencies": {
|
|
@@ -221,5 +221,5 @@
|
|
|
221
221
|
"nyc": {
|
|
222
222
|
"extends": "../../configs/nyc.json"
|
|
223
223
|
},
|
|
224
|
-
"gitHead": "
|
|
224
|
+
"gitHead": "5f7caff6d4a136452787442612656962b5c5099e"
|
|
225
225
|
}
|
|
@@ -718,8 +718,8 @@ export class CommonFrontendContribution implements FrontendApplicationContributi
|
|
|
718
718
|
execute: title => title?.owner && this.shell.toggleMaximized(title?.owner),
|
|
719
719
|
}));
|
|
720
720
|
commandRegistry.registerCommand(CommonCommands.SHOW_MENU_BAR, {
|
|
721
|
-
isEnabled: () => !isOSX,
|
|
722
|
-
isVisible: () => !isOSX,
|
|
721
|
+
isEnabled: () => !this.isElectron() || !isOSX,
|
|
722
|
+
isVisible: () => !this.isElectron() || !isOSX,
|
|
723
723
|
execute: () => {
|
|
724
724
|
const menuBarVisibility = 'window.menuBarVisibility';
|
|
725
725
|
const visibility = this.preferences[menuBarVisibility];
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
|
|
17
17
|
import * as React from 'react';
|
|
18
|
+
import { buttonKeyboardProps, isActivationKey } from '../keyboard/keyboard-utils';
|
|
18
19
|
|
|
19
20
|
export interface CardActionButton {
|
|
20
21
|
/** Icon class (e.g., codicon) */
|
|
@@ -69,14 +70,22 @@ export const Card = React.memo(function Card(props: CardProps): React.ReactEleme
|
|
|
69
70
|
} = props;
|
|
70
71
|
|
|
71
72
|
const isInteractive = onClick !== undefined;
|
|
73
|
+
const [hasFocus, setHasFocus] = React.useState(false);
|
|
72
74
|
|
|
73
75
|
const handleKeyDown = React.useCallback((e: React.KeyboardEvent<HTMLDivElement>) => {
|
|
74
|
-
if (onClick && (e
|
|
76
|
+
if (onClick && isActivationKey(e)) {
|
|
75
77
|
e.preventDefault();
|
|
76
78
|
onClick();
|
|
77
79
|
}
|
|
78
80
|
}, [onClick]);
|
|
79
81
|
|
|
82
|
+
const handleFocus = React.useCallback(() => setHasFocus(true), []);
|
|
83
|
+
const handleBlur = React.useCallback((e: React.FocusEvent<HTMLDivElement>) => {
|
|
84
|
+
if (!e.currentTarget.contains(e.relatedTarget as Node)) {
|
|
85
|
+
setHasFocus(false);
|
|
86
|
+
}
|
|
87
|
+
}, []);
|
|
88
|
+
|
|
80
89
|
const cardClasses = [
|
|
81
90
|
'theia-Card',
|
|
82
91
|
isInteractive && 'theia-Card-interactive',
|
|
@@ -94,6 +103,8 @@ export const Card = React.memo(function Card(props: CardProps): React.ReactEleme
|
|
|
94
103
|
role={isInteractive ? 'button' : undefined}
|
|
95
104
|
tabIndex={isInteractive ? 0 : undefined}
|
|
96
105
|
onKeyDown={isInteractive ? handleKeyDown : undefined}
|
|
106
|
+
onFocus={actionButtons ? handleFocus : undefined}
|
|
107
|
+
onBlur={actionButtons ? handleBlur : undefined}
|
|
97
108
|
>
|
|
98
109
|
{icon && (
|
|
99
110
|
<div className={`theia-Card-icon ${icon}`}></div>
|
|
@@ -115,7 +126,7 @@ export const Card = React.memo(function Card(props: CardProps): React.ReactEleme
|
|
|
115
126
|
key={i}
|
|
116
127
|
className={`theia-Card-action-btn ${btn.iconClass}`}
|
|
117
128
|
title={btn.title}
|
|
118
|
-
|
|
129
|
+
{...buttonKeyboardProps(btn.title, hasFocus ? 0 : -1)}
|
|
119
130
|
onClick={btn.onClick}
|
|
120
131
|
/>
|
|
121
132
|
))}
|
|
@@ -205,7 +205,7 @@ export class ApplicationConnectionStatusContribution extends DefaultFrontendAppl
|
|
|
205
205
|
protected handleOffline(): void {
|
|
206
206
|
this.statusBar.setElement(this.statusbarId, {
|
|
207
207
|
alignment: StatusBarAlignment.LEFT,
|
|
208
|
-
text: nls.
|
|
208
|
+
text: nls.localizeByDefault('Offline'),
|
|
209
209
|
tooltip: nls.localize('theia/localize/offlineTooltip', 'Cannot connect to backend.'),
|
|
210
210
|
priority: 5000
|
|
211
211
|
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2026 EclipseSource 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
|
+
/**
|
|
18
|
+
* Query whether the keyboard event represents an element activation.
|
|
19
|
+
* That is, whether the user pressed `Enter` or `Space` on a focusable
|
|
20
|
+
* element with `role="button"` or similar interactive role.
|
|
21
|
+
*/
|
|
22
|
+
export function isActivationKey(e: React.KeyboardEvent | KeyboardEvent): boolean {
|
|
23
|
+
return e.key === 'Enter' || e.key === ' ';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Returns the ARIA/accessibility props that make a non-button HTML element
|
|
28
|
+
* keyboard-navigable and screen-reader-accessible as a button.
|
|
29
|
+
*
|
|
30
|
+
* Spread these onto the element alongside `onClick` and `onKeyDown`:
|
|
31
|
+
* ```tsx
|
|
32
|
+
* <div {...buttonKeyboardProps(label)} onClick={handler} onKeyDown={e => isActivationKey(e) && handler()} />
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export function buttonKeyboardProps(ariaLabel: string, tabIndex = 0): React.HTMLAttributes<HTMLElement> {
|
|
36
|
+
return { tabIndex, role: 'button', 'aria-label': ariaLabel };
|
|
37
|
+
}
|
|
@@ -143,7 +143,14 @@ export class DynamicMenuBarWidget extends MenuBarWidget {
|
|
|
143
143
|
protected previousFocusedElement: HTMLElement | undefined;
|
|
144
144
|
|
|
145
145
|
constructor() {
|
|
146
|
-
|
|
146
|
+
// Disable Lumino's overflow menu feature. The feature has a bug where
|
|
147
|
+
// `onUpdateRequest` consumes a stale `_overflowIndex` (only recomputed at the
|
|
148
|
+
// end of the method), which causes a RangeError when the menu bar is rendered
|
|
149
|
+
// at zero width. Additionally, Theia's CSS does not constrain the menu bar's
|
|
150
|
+
// offsetWidth to the available space, so the overflow detection never triggers.
|
|
151
|
+
// See https://github.com/eclipse-theia/theia/issues/17352
|
|
152
|
+
// See https://github.com/jupyterlab/lumino/issues/811
|
|
153
|
+
super({ overflowMenuOptions: { isVisible: false } });
|
|
147
154
|
// HACK we need to hook in on private method _openChildMenu. Don't do this at home!
|
|
148
155
|
DynamicMenuBarWidget.prototype['_openChildMenu'] = () => {
|
|
149
156
|
if (this.activeMenu instanceof DynamicMenuWidget) {
|
|
@@ -21,10 +21,13 @@ import { LocalConnectionProvider, RemoteConnectionProvider, ServiceConnectionPro
|
|
|
21
21
|
import { ConnectionSource } from './connection-source';
|
|
22
22
|
import { ConnectionCloseService, connectionCloseServicePath } from '../../common/messaging/connection-management';
|
|
23
23
|
import { WebSocketConnectionProvider } from './ws-connection-provider';
|
|
24
|
+
import { SocketWriteBuffer } from '../../common/messaging/socket-write-buffer';
|
|
24
25
|
|
|
25
26
|
const backendServiceProvider = Symbol('backendServiceProvider');
|
|
26
27
|
|
|
27
28
|
export const messagingFrontendModule = new ContainerModule(bind => {
|
|
29
|
+
// Transient: each connection source gets its own private buffer instance.
|
|
30
|
+
bind(SocketWriteBuffer).toSelf();
|
|
28
31
|
bind(ConnectionCloseService).toDynamicValue(ctx => WebSocketConnectionProvider.createProxy(ctx.container, connectionCloseServicePath)).inSingletonScope();
|
|
29
32
|
bind(BrowserFrontendIdProvider).toSelf().inSingletonScope();
|
|
30
33
|
bind(FrontendIdProvider).toService(BrowserFrontendIdProvider);
|
|
@@ -33,7 +33,8 @@ export class WebSocketConnectionSource implements ConnectionSource {
|
|
|
33
33
|
@inject(FrontendIdProvider)
|
|
34
34
|
protected readonly frontendIdProvider: FrontendIdProvider;
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
@inject(SocketWriteBuffer)
|
|
37
|
+
protected readonly writeBuffer: SocketWriteBuffer;
|
|
37
38
|
|
|
38
39
|
private _socket: Socket;
|
|
39
40
|
get socket(): Socket {
|
|
@@ -135,8 +136,8 @@ export class WebSocketConnectionSource implements ConnectionSource {
|
|
|
135
136
|
|
|
136
137
|
connectNewChannel(): void {
|
|
137
138
|
if (this.currentChannel) {
|
|
138
|
-
this.currentChannel.close();
|
|
139
139
|
this.currentChannel.onCloseEmitter.fire({ reason: 'reconnecting channel' });
|
|
140
|
+
this.currentChannel.close();
|
|
140
141
|
}
|
|
141
142
|
this.writeBuffer.drain();
|
|
142
143
|
this.currentChannel = this.createChannel();
|
|
@@ -22,6 +22,7 @@ import { AutoSaveMode, Saveable, SaveableSource, SaveableWidget, SaveOptions, Sa
|
|
|
22
22
|
import { waitForClosed, Widget } from './widgets';
|
|
23
23
|
import { FrontendApplicationContribution } from './frontend-application-contribution';
|
|
24
24
|
import { FrontendApplication } from './frontend-application';
|
|
25
|
+
import { WindowFocusService } from './window/window-focus-service';
|
|
25
26
|
import throttle = require('lodash.throttle');
|
|
26
27
|
|
|
27
28
|
export const SaveErrorChecker = Symbol('SaveErrorChecker');
|
|
@@ -49,6 +50,9 @@ export class SaveableService implements FrontendApplicationContribution {
|
|
|
49
50
|
@inject(ContributionProvider) @named(SaveErrorChecker)
|
|
50
51
|
protected readonly errorCheckers: ContributionProvider<SaveErrorChecker>;
|
|
51
52
|
|
|
53
|
+
@inject(WindowFocusService)
|
|
54
|
+
protected readonly windowFocusService: WindowFocusService;
|
|
55
|
+
|
|
52
56
|
protected saveThrottles = new Map<Widget, AutoSaveThrottle>();
|
|
53
57
|
protected saveMode: AutoSaveMode = 'off';
|
|
54
58
|
protected saveDelay = 1000;
|
|
@@ -131,6 +135,35 @@ export class SaveableService implements FrontendApplicationContribution {
|
|
|
131
135
|
this.saveThrottles.get(e)?.dispose();
|
|
132
136
|
this.saveThrottles.delete(e);
|
|
133
137
|
});
|
|
138
|
+
// Save all dirty editors when any application window loses focus
|
|
139
|
+
this.windowFocusService.onDidWindowChangeFocus(({ hasFocus }) => {
|
|
140
|
+
if (!hasFocus) {
|
|
141
|
+
this.saveOnWindowBlur();
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Save all dirty saveables when the application window loses focus.
|
|
148
|
+
* Triggered for both `onFocusChange` and `onWindowChange` auto-save modes,
|
|
149
|
+
* matching VSCode's behavior where a window focus loss is a superset of
|
|
150
|
+
* editor focus loss.
|
|
151
|
+
*/
|
|
152
|
+
protected saveOnWindowBlur(): void {
|
|
153
|
+
if (this.saveMode !== 'onWindowChange' && this.saveMode !== 'onFocusChange') {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (!this.shell) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
for (const widget of this.shell.widgets) {
|
|
160
|
+
const saveable = Saveable.get(widget);
|
|
161
|
+
if (saveable && this.shouldAutoSave(widget, saveable)) {
|
|
162
|
+
saveable.save({
|
|
163
|
+
saveReason: SaveReason.FocusChange
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
134
167
|
}
|
|
135
168
|
|
|
136
169
|
protected updateAutoSaveMode(mode: AutoSaveMode): void {
|
|
@@ -169,39 +202,13 @@ export class SaveableService implements FrontendApplicationContribution {
|
|
|
169
202
|
saveReason: SaveReason.AfterDelay
|
|
170
203
|
});
|
|
171
204
|
}
|
|
172
|
-
}
|
|
173
|
-
this.addBlurListener(widget, saveable)
|
|
205
|
+
}
|
|
174
206
|
);
|
|
175
207
|
this.saveThrottles.set(widget, saveThrottle);
|
|
176
208
|
this.applySaveableWidget(widget, saveable);
|
|
177
209
|
return saveThrottle;
|
|
178
210
|
}
|
|
179
211
|
|
|
180
|
-
protected addBlurListener(widget: Widget, saveable: Saveable): Disposable {
|
|
181
|
-
const document = widget.node.ownerDocument;
|
|
182
|
-
const listener = (() => {
|
|
183
|
-
if (this.saveMode === 'onWindowChange' && !this.windowHasFocus(document) && this.shouldAutoSave(widget, saveable)) {
|
|
184
|
-
saveable.save({
|
|
185
|
-
saveReason: SaveReason.FocusChange
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
}).bind(this);
|
|
189
|
-
document.addEventListener('blur', listener);
|
|
190
|
-
return Disposable.create(() => {
|
|
191
|
-
document.removeEventListener('blur', listener);
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
protected windowHasFocus(document: Document): boolean {
|
|
196
|
-
if (document.visibilityState === 'hidden') {
|
|
197
|
-
return false;
|
|
198
|
-
} else if (document.hasFocus()) {
|
|
199
|
-
return true;
|
|
200
|
-
}
|
|
201
|
-
// TODO: Add support for iframes
|
|
202
|
-
return false;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
212
|
protected shouldAutoSave(widget: Widget, saveable: Saveable): boolean {
|
|
206
213
|
const uri = NavigatableWidget.getUri(widget);
|
|
207
214
|
if (uri?.scheme === UNTITLED_SCHEME) {
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
import { inject, injectable, postConstruct } from 'inversify';
|
|
18
18
|
import * as React from 'react';
|
|
19
|
+
import { buttonKeyboardProps, isActivationKey } from '../../keyboard/keyboard-utils';
|
|
19
20
|
import { ContextKeyService } from '../../context-key-service';
|
|
20
21
|
import { CommandRegistry, Disposable, DisposableCollection, nls } from '../../../common';
|
|
21
22
|
import { Anchor, ContextMenuAccess, ContextMenuRenderer } from '../../context-menu-renderer';
|
|
@@ -150,7 +151,10 @@ export class TabBarToolbar extends ReactWidget {
|
|
|
150
151
|
|
|
151
152
|
protected renderMore(): React.ReactNode {
|
|
152
153
|
return !!this.more.size && <div key='__more__' className={TabBarToolbar.Styles.TAB_BAR_TOOLBAR_ITEM + ' enabled'}>
|
|
153
|
-
<div id='__more__' className={codicon('ellipsis', true)}
|
|
154
|
+
<div id='__more__' className={codicon('ellipsis', true)}
|
|
155
|
+
{...buttonKeyboardProps(nls.localizeByDefault('More Actions...'))}
|
|
156
|
+
onClick={this.showMoreContextMenu}
|
|
157
|
+
onKeyDown={this.handleMoreKeyDown}
|
|
154
158
|
title={nls.localizeByDefault('More Actions...')} />
|
|
155
159
|
</div>;
|
|
156
160
|
}
|
|
@@ -162,6 +166,15 @@ export class TabBarToolbar extends ReactWidget {
|
|
|
162
166
|
this.renderMoreContextMenu(anchor);
|
|
163
167
|
};
|
|
164
168
|
|
|
169
|
+
protected handleMoreKeyDown = (event: React.KeyboardEvent) => {
|
|
170
|
+
if (isActivationKey(event)) {
|
|
171
|
+
event.preventDefault();
|
|
172
|
+
event.stopPropagation();
|
|
173
|
+
const { left, bottom } = (event.currentTarget as HTMLElement).getBoundingClientRect();
|
|
174
|
+
this.renderMoreContextMenu({ x: left, y: bottom });
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
|
|
165
178
|
renderMoreContextMenu(anchor: Anchor): ContextMenuAccess {
|
|
166
179
|
const toDisposeOnHide = new DisposableCollection();
|
|
167
180
|
this.addClass('menu-open');
|
|
@@ -23,6 +23,7 @@ import { KeybindingRegistry } from '../../keybinding';
|
|
|
23
23
|
import { ACTION_ITEM } from '../../widgets';
|
|
24
24
|
import { TabBarToolbar } from './tab-bar-toolbar';
|
|
25
25
|
import * as React from 'react';
|
|
26
|
+
import { buttonKeyboardProps, isActivationKey } from '../../keyboard/keyboard-utils';
|
|
26
27
|
import { ActionMenuNode, GroupImpl, MenuNode } from '../../../common/menu';
|
|
27
28
|
|
|
28
29
|
export interface TabBarToolbarItem {
|
|
@@ -195,16 +196,24 @@ export class RenderedToolbarItemImpl extends AbstractToolbarItemImpl<RenderedToo
|
|
|
195
196
|
};
|
|
196
197
|
|
|
197
198
|
protected executeCommand(e: React.MouseEvent<HTMLElement>, widget: Widget): void {
|
|
199
|
+
this.doExecuteCommand(e, widget);
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
protected doExecuteCommand(e: React.SyntheticEvent<HTMLElement>, widget: Widget): void {
|
|
198
203
|
e.preventDefault();
|
|
199
204
|
e.stopPropagation();
|
|
200
|
-
|
|
201
205
|
if (!this.isEnabled(widget)) {
|
|
202
206
|
return;
|
|
203
207
|
}
|
|
204
|
-
|
|
205
208
|
if (this.action.command) {
|
|
206
209
|
this.commandRegistry.executeCommand(this.action.command, widget);
|
|
207
210
|
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
protected onKeyDownEvent = (e: React.KeyboardEvent<HTMLElement>, widget: Widget) => {
|
|
214
|
+
if (isActivationKey(e)) {
|
|
215
|
+
this.doExecuteCommand(e, widget);
|
|
216
|
+
}
|
|
208
217
|
};
|
|
209
218
|
|
|
210
219
|
protected renderItem(widget: Widget): React.ReactNode {
|
|
@@ -249,7 +258,9 @@ export class RenderedToolbarItemImpl extends AbstractToolbarItemImpl<RenderedToo
|
|
|
249
258
|
onMouseUp={this.onMouseUpEvent}
|
|
250
259
|
onMouseOut={this.onMouseUpEvent} >
|
|
251
260
|
<div id={this.action.id} className={classNames.join(' ')}
|
|
261
|
+
{...buttonKeyboardProps(tooltip)}
|
|
252
262
|
onClick={e => this.executeCommand(e, widget)}
|
|
263
|
+
onKeyDown={e => this.onKeyDownEvent(e, widget)}
|
|
253
264
|
title={tooltip} > {innerText}
|
|
254
265
|
</div>
|
|
255
266
|
</div>;
|
|
@@ -101,11 +101,13 @@
|
|
|
101
101
|
transition: opacity 0.15s;
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
.theia-Card:hover .theia-Card-footer-time
|
|
104
|
+
.theia-Card:hover .theia-Card-footer-time,
|
|
105
|
+
.theia-Card:focus-within .theia-Card-footer-time {
|
|
105
106
|
opacity: 0;
|
|
106
107
|
}
|
|
107
108
|
|
|
108
|
-
.theia-Card:hover .theia-Card-footer-actions
|
|
109
|
+
.theia-Card:hover .theia-Card-footer-actions,
|
|
110
|
+
.theia-Card:focus-within .theia-Card-footer-actions {
|
|
109
111
|
opacity: 1;
|
|
110
112
|
pointer-events: auto;
|
|
111
113
|
}
|
|
@@ -30,6 +30,8 @@
|
|
|
30
30
|
padding: var(--theia-ui-padding);
|
|
31
31
|
max-width: var(--theia-hover-max-width);
|
|
32
32
|
user-select: text;
|
|
33
|
+
--vscode-scmGraph-historyItemHoverAdditionsForeground: var(--theia-scmGraph-historyItemHoverAdditionsForeground);
|
|
34
|
+
--vscode-scmGraph-historyItemHoverDeletionsForeground: var(--theia-scmGraph-historyItemHoverDeletionsForeground);
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
/* overwrite potentially different default user agent styles */
|
|
@@ -60,6 +62,11 @@
|
|
|
60
62
|
background-color: var(--theia-editorHoverWidget-statusBarBackground);
|
|
61
63
|
}
|
|
62
64
|
|
|
65
|
+
.theia-hover .codicon {
|
|
66
|
+
vertical-align: middle;
|
|
67
|
+
margin-bottom: 2px;
|
|
68
|
+
}
|
|
69
|
+
|
|
63
70
|
.theia-hover code {
|
|
64
71
|
background-color: var(--theia-textCodeBlock-background);
|
|
65
72
|
font-family: var(--theia-code-font-family);
|
|
@@ -24,6 +24,7 @@ import { SecondaryWindowService } from './secondary-window-service';
|
|
|
24
24
|
import { DefaultSecondaryWindowService } from './default-secondary-window-service';
|
|
25
25
|
import { bindRootContributionProvider } from '../../common';
|
|
26
26
|
import { WindowTitleContribution } from './window-title-service';
|
|
27
|
+
import { WindowFocusService } from './window-focus-service';
|
|
27
28
|
|
|
28
29
|
export default new ContainerModule(bind => {
|
|
29
30
|
bind(DefaultWindowService).toSelf().inSingletonScope();
|
|
@@ -31,5 +32,6 @@ export default new ContainerModule(bind => {
|
|
|
31
32
|
bind(FrontendApplicationContribution).toService(DefaultWindowService);
|
|
32
33
|
bind(ClipboardService).to(BrowserClipboardService).inSingletonScope();
|
|
33
34
|
bind(SecondaryWindowService).to(DefaultSecondaryWindowService).inSingletonScope();
|
|
35
|
+
bind(WindowFocusService).toSelf().inSingletonScope();
|
|
34
36
|
bindRootContributionProvider(bind, WindowTitleContribution);
|
|
35
37
|
});
|
|
@@ -22,6 +22,7 @@ import { Saveable } from '../saveable';
|
|
|
22
22
|
import { Emitter, environment, Event, PreferenceService } from '../../common';
|
|
23
23
|
import { SaveableService } from '../saveable-service';
|
|
24
24
|
import { getAllWidgetsFromSecondaryWindow, getDefaultRestoreArea } from '../secondary-window-handler';
|
|
25
|
+
import { WindowFocusService } from './window-focus-service';
|
|
25
26
|
|
|
26
27
|
@injectable()
|
|
27
28
|
export class DefaultSecondaryWindowService implements SecondaryWindowService {
|
|
@@ -53,6 +54,9 @@ export class DefaultSecondaryWindowService implements SecondaryWindowService {
|
|
|
53
54
|
@inject(SaveableService)
|
|
54
55
|
protected readonly saveResourceService: SaveableService;
|
|
55
56
|
|
|
57
|
+
@inject(WindowFocusService)
|
|
58
|
+
protected readonly windowFocusService: WindowFocusService;
|
|
59
|
+
|
|
56
60
|
@postConstruct()
|
|
57
61
|
init(): void {
|
|
58
62
|
// Set up messaging with secondary windows
|
|
@@ -106,6 +110,7 @@ export class DefaultSecondaryWindowService implements SecondaryWindowService {
|
|
|
106
110
|
this.secondaryWindows.push(newWindow);
|
|
107
111
|
this.onWindowOpenedEmitter.fire(newWindow);
|
|
108
112
|
newWindow.addEventListener('DOMContentLoaded', () => {
|
|
113
|
+
const focusRegistration = this.windowFocusService.registerWindow(newWindow);
|
|
109
114
|
newWindow.addEventListener('beforeunload', evt => {
|
|
110
115
|
const widgets = getAllWidgetsFromSecondaryWindow(newWindow) ?? [widget];
|
|
111
116
|
for (const w of widgets) {
|
|
@@ -120,6 +125,7 @@ export class DefaultSecondaryWindowService implements SecondaryWindowService {
|
|
|
120
125
|
}, { capture: true });
|
|
121
126
|
|
|
122
127
|
newWindow.addEventListener('unload', () => {
|
|
128
|
+
focusRegistration.dispose();
|
|
123
129
|
const extIndex = this.secondaryWindows.indexOf(newWindow);
|
|
124
130
|
if (extIndex > -1) {
|
|
125
131
|
this.onWindowClosedEmitter.fire(newWindow);
|