@theia/core 1.64.0-next.0 → 1.64.0-next.28

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 (63) hide show
  1. package/README.md +1 -1
  2. package/lib/browser/catalog.json +782 -725
  3. package/lib/browser/hover-service.d.ts +9 -3
  4. package/lib/browser/hover-service.d.ts.map +1 -1
  5. package/lib/browser/hover-service.js +25 -13
  6. package/lib/browser/hover-service.js.map +1 -1
  7. package/lib/browser/menu/browser-menu-plugin.js +1 -1
  8. package/lib/browser/menu/browser-menu-plugin.js.map +1 -1
  9. package/lib/browser/saveable-service.d.ts.map +1 -1
  10. package/lib/browser/saveable-service.js +4 -0
  11. package/lib/browser/saveable-service.js.map +1 -1
  12. package/lib/browser/shell/tab-bar-toolbar/tab-toolbar-item.d.ts.map +1 -1
  13. package/lib/browser/shell/tab-bar-toolbar/tab-toolbar-item.js +5 -0
  14. package/lib/browser/shell/tab-bar-toolbar/tab-toolbar-item.js.map +1 -1
  15. package/lib/browser/status-bar/status-bar.d.ts +2 -1
  16. package/lib/browser/status-bar/status-bar.d.ts.map +1 -1
  17. package/lib/browser/status-bar/status-bar.js +14 -7
  18. package/lib/browser/status-bar/status-bar.js.map +1 -1
  19. package/lib/browser/tree/tree-widget.d.ts +8 -0
  20. package/lib/browser/tree/tree-widget.d.ts.map +1 -1
  21. package/lib/browser/tree/tree-widget.js +38 -26
  22. package/lib/browser/tree/tree-widget.js.map +1 -1
  23. package/lib/browser/widgets/alert-message.js +1 -2
  24. package/lib/browser/widgets/alert-message.js.map +1 -1
  25. package/lib/browser/widgets/select-component.d.ts +2 -0
  26. package/lib/browser/widgets/select-component.d.ts.map +1 -1
  27. package/lib/browser/widgets/select-component.js +1 -1
  28. package/lib/browser/widgets/select-component.js.map +1 -1
  29. package/lib/electron-main/electron-main-application.d.ts.map +1 -1
  30. package/lib/electron-main/electron-main-application.js +21 -7
  31. package/lib/electron-main/electron-main-application.js.map +1 -1
  32. package/lib/node/setting-service.d.ts +5 -1
  33. package/lib/node/setting-service.d.ts.map +1 -1
  34. package/lib/node/setting-service.js +25 -10
  35. package/lib/node/setting-service.js.map +1 -1
  36. package/lib/node/setting-service.spec.d.ts +2 -0
  37. package/lib/node/setting-service.spec.d.ts.map +1 -0
  38. package/lib/node/setting-service.spec.js +84 -0
  39. package/lib/node/setting-service.spec.js.map +1 -0
  40. package/package.json +4 -4
  41. package/src/browser/hover-service.ts +31 -13
  42. package/src/browser/menu/browser-menu-plugin.ts +1 -1
  43. package/src/browser/saveable-service.ts +4 -0
  44. package/src/browser/shell/tab-bar-toolbar/tab-toolbar-item.tsx +8 -0
  45. package/src/browser/status-bar/status-bar.tsx +14 -7
  46. package/src/browser/style/alert-messages.css +20 -17
  47. package/src/browser/style/breadcrumbs.css +1 -2
  48. package/src/browser/style/dialog.css +3 -2
  49. package/src/browser/style/index.css +5 -3
  50. package/src/browser/style/progress-bar.css +3 -0
  51. package/src/browser/style/select-component.css +1 -4
  52. package/src/browser/style/sidepanel.css +10 -14
  53. package/src/browser/style/split-widget.css +4 -0
  54. package/src/browser/style/status-bar.css +23 -20
  55. package/src/browser/style/tabs.css +15 -13
  56. package/src/browser/style/tree.css +5 -3
  57. package/src/browser/style/view-container.css +3 -7
  58. package/src/browser/tree/tree-widget.tsx +50 -27
  59. package/src/browser/widgets/alert-message.tsx +2 -2
  60. package/src/browser/widgets/select-component.tsx +4 -1
  61. package/src/electron-main/electron-main-application.ts +22 -7
  62. package/src/node/setting-service.spec.ts +97 -0
  63. package/src/node/setting-service.ts +25 -11
@@ -123,8 +123,10 @@ blockquote {
123
123
  font-family: var(--theia-ui-font-family);
124
124
  font-size: var(--theia-ui-font-size1);
125
125
  line-height: var(--theia-content-line-height);
126
- padding-left: 5px;
126
+ padding: 3px 0 3px 8px;
127
127
  border-radius: 2px;
128
+ min-height: 28px;
129
+ box-sizing: border-box;
128
130
  }
129
131
 
130
132
  .theia-input[type="text"] {
@@ -248,7 +250,7 @@ blockquote {
248
250
 
249
251
  .action-label {
250
252
  padding: 2px;
251
- border-radius: 5px;
253
+ border-radius: 4px;
252
254
  cursor: pointer;
253
255
  }
254
256
 
@@ -262,7 +264,7 @@ blockquote {
262
264
  min-width: 65px;
263
265
  outline: none;
264
266
  cursor: pointer;
265
- padding: 4px 9px;
267
+ padding: 6px 9px;
266
268
  margin-left: calc(var(--theia-ui-padding) * 2);
267
269
  border-radius: 2px;
268
270
  }
@@ -15,6 +15,9 @@
15
15
  ********************************************************************************/
16
16
 
17
17
  .theia-progress-bar-container {
18
+ position: absolute;
19
+ top: -2px;
20
+ left: 0;
18
21
  width: 100%;
19
22
  height: 2px;
20
23
  }
@@ -43,10 +43,6 @@
43
43
  overflow: hidden;
44
44
  }
45
45
 
46
- .theia-select-component:focus {
47
- outline-color: var(--theia-focusBorder);
48
- }
49
-
50
46
  .theia-select-component-dropdown {
51
47
  font-family: var(--theia-ui-font-family);
52
48
  font-size: var(--theia-ui-font-size1);
@@ -57,6 +53,7 @@
57
53
  user-select: none;
58
54
  overflow: auto;
59
55
  border-radius: 2px;
56
+ margin-top: 2px;
60
57
  }
61
58
 
62
59
  .theia-select-component-dropdown .theia-select-component-option {
@@ -35,7 +35,6 @@
35
35
  .lm-TabBar.theia-app-sides {
36
36
  display: block;
37
37
  color: var(--theia-activityBar-inactiveForeground);
38
- background: var(--theia-activityBar-background);
39
38
  font-size: var(--theia-ui-font-size1);
40
39
  min-width: var(--theia-private-sidebar-tab-width);
41
40
  max-width: var(--theia-private-sidebar-tab-width);
@@ -52,7 +51,6 @@
52
51
 
53
52
  .lm-TabBar.theia-app-sides .lm-TabBar-tab {
54
53
  position: relative;
55
- background: var(--theia-activityBar-background);
56
54
  flex-direction: column;
57
55
  justify-content: center;
58
56
  align-items: center;
@@ -146,6 +144,14 @@
146
144
  max-width: var(--theia-private-sidebar-tab-width);
147
145
  }
148
146
 
147
+ #theia-left-content-panel.theia-mod-collapsed .theia-app-sidebar-container {
148
+ border-right: none;
149
+ }
150
+
151
+ #theia-right-content-panel.theia-mod-collapsed .theia-app-sidebar-container {
152
+ border-left: none;
153
+ }
154
+
149
155
  #theia-left-content-panel > .lm-Panel {
150
156
  border-right: var(--theia-panel-border-width) solid
151
157
  var(--theia-activityBar-border);
@@ -326,13 +332,9 @@
326
332
  |----------------------------------------------------------------------------*/
327
333
 
328
334
  .theia-sidepanel-toolbar {
329
- min-height: calc(
330
- var(--theia-private-horizontal-tab-height) +
331
- var(--theia-private-horizontal-tab-scrollbar-rail-height) / 2
332
- );
333
335
  display: flex;
334
- padding-left: 5px;
335
336
  align-items: center;
337
+ min-height: var(--theia-horizontal-toolbar-height);
336
338
  background-color: var(--theia-sideBar-background);
337
339
  overflow: hidden;
338
340
  }
@@ -340,7 +342,7 @@
340
342
  .theia-sidepanel-toolbar .theia-sidepanel-title {
341
343
  color: var(--theia-settings-headerForeground);
342
344
  flex: 1;
343
- margin-left: 14px;
345
+ margin-left: calc(var(--theia-ui-padding) * 3);
344
346
  text-transform: uppercase;
345
347
  font-size: var(--theia-ui-font-size0);
346
348
  min-width: 1rem;
@@ -350,12 +352,6 @@
350
352
  color: var(--theia-icon-foreground);
351
353
  }
352
354
 
353
- .theia-sidepanel-toolbar .lm-TabBar-toolbar .item > div {
354
- height: 18px;
355
- width: 18px;
356
- background-repeat: no-repeat;
357
- }
358
-
359
355
  .noWrapInfo {
360
356
  white-space: nowrap;
361
357
  overflow: hidden;
@@ -25,6 +25,10 @@
25
25
  min-height: var(--theia-content-line-height);
26
26
  }
27
27
 
28
+ .lm-SplitPanel-handle {
29
+ z-index: 6; /* Upper than the minimap */
30
+ }
31
+
28
32
  .theia-split-widget > .lm-SplitPanel > .lm-SplitPanel-handle {
29
33
  box-sizing: border-box;
30
34
  }
@@ -37,60 +37,63 @@ body.theia-no-open-workspace #theia-statusBar {
37
37
  flex: 1;
38
38
  display: flex;
39
39
  align-items: stretch;
40
+ gap: var(--theia-ui-padding)
40
41
  }
41
42
 
42
43
  #theia-statusBar .area.left {
43
44
  justify-content: flex-start;
45
+ padding-left: var(--theia-ui-padding);
44
46
  }
45
47
 
46
48
  #theia-statusBar .area.right {
47
49
  justify-content: flex-end;
48
- padding-right: calc(var(--theia-ui-padding) * 2);
50
+ padding-right: var(--theia-ui-padding);
49
51
  }
50
52
 
51
53
  #theia-statusBar .area .element {
52
54
  color: var(--theia-statusBar-foreground);
53
55
  display: flex;
54
56
  align-items: center;
57
+ justify-content: center;
55
58
  font-size: var(--theia-statusBar-font-size);
59
+ min-width: var(--theia-statusBar-height);
56
60
  }
57
61
 
58
62
  #theia-statusBar .area.left .element.has-background {
59
- margin-left: 0px;
60
- margin-right: 3px;
61
- padding-left: 7px;
62
- padding-right: 7px;
63
+ padding-inline: var(--theia-ui-padding);
63
64
  }
64
- #theia-statusBar .area .element>* {
65
- margin-left: calc(var(--theia-ui-padding)/2);
65
+
66
+ #theia-statusBar .area.left .element.has-background {
67
+ margin-left: calc(-1 * var(--theia-ui-padding));
66
68
  }
67
69
 
70
+ /* Icons */
68
71
  #theia-statusBar .area .element .codicon {
69
72
  /* Scaling down codicons from 16 to 14 pixels */
70
73
  font-size: 14px;
74
+ margin: auto;
71
75
  }
72
76
 
73
- #theia-statusBar .area .element > *:last-child {
74
- margin-right: calc(var(--theia-ui-padding) / 2);
77
+ /* Icon with text */
78
+ #theia-statusBar .area .element .codicon:has(+ span) {
79
+ margin-inline: calc(var(--theia-ui-padding) / 2);
75
80
  }
76
81
 
77
- .theia-mod-offline #theia-statusBar {
78
- background-color: var(--theia-statusBar-offlineBackground) !important;
82
+ /* Text labels */
83
+ #theia-statusBar .area .element>span:not(.codicon) {
84
+ margin-inline: calc(var(--theia-ui-padding) / 2)
79
85
  }
80
86
 
81
- .theia-mod-offline #theia-statusBar .area .element {
82
- color: var(--theia-statusBar-offlineForeground) !important;
87
+ #theia-statusBar .area .element>span:not(.codicon):empty {
88
+ display: none;
83
89
  }
84
90
 
85
- #theia-statusBar .area.left .element:first-child:not(.has-background) {
86
- margin-left: calc(var(--theia-ui-padding) * 3);
87
- }
88
- #theia-statusBar .area.left .element {
89
- margin-right: var(--theia-ui-padding);
91
+ .theia-mod-offline #theia-statusBar {
92
+ background-color: var(--theia-statusBar-offlineBackground) !important;
90
93
  }
91
94
 
92
- #theia-statusBar .area.right .element {
93
- margin-left: var(--theia-ui-padding);
95
+ .theia-mod-offline #theia-statusBar .area .element {
96
+ color: var(--theia-statusBar-offlineForeground) !important;
94
97
  }
95
98
 
96
99
  #theia-statusBar .area.right .element.compact-right,
@@ -4,12 +4,12 @@
4
4
 
5
5
  :root {
6
6
  /* These need to be root because tabs get attached to the body during dragging. */
7
- --theia-private-horizontal-tab-height: 28.5px;
7
+ --theia-private-horizontal-tab-height: 35px;
8
+ --theia-horizontal-toolbar-height: var(--theia-private-horizontal-tab-height);
8
9
  --theia-private-horizontal-tab-scrollbar-rail-height: 7px;
9
10
  --theia-private-horizontal-tab-scrollbar-height: 5px;
10
11
  --theia-tabbar-toolbar-z-index: 1001;
11
12
  --theia-toolbar-active-transform-scale: 1.272019649;
12
- --theia-horizontal-toolbar-height: calc(var(--theia-private-horizontal-tab-height) + var(--theia-private-horizontal-tab-scrollbar-rail-height) / 2);
13
13
  --theia-dragover-tab-border-width: 2px;
14
14
  }
15
15
 
@@ -32,8 +32,8 @@
32
32
  .lm-TabBar[data-orientation="horizontal"] .lm-TabBar-tab {
33
33
  flex: none;
34
34
  height: var(--theia-horizontal-toolbar-height);
35
+ line-height: var(--theia-horizontal-toolbar-height);
35
36
  min-width: 35px;
36
- line-height: var(--theia-private-horizontal-tab-height);
37
37
  padding: 0px 8px;
38
38
  align-items: center;
39
39
  overflow: hidden;
@@ -221,7 +221,6 @@
221
221
  .lm-TabBar.theia-app-centers .lm-TabBar-tab.lm-mod-closable>.lm-TabBar-tabCloseIcon,
222
222
  .lm-TabBar.theia-app-centers .lm-TabBar-tab.theia-mod-pinned>.lm-TabBar-tabCloseIcon {
223
223
  padding: 2px;
224
- margin-top: 2px;
225
224
  margin-left: 4px;
226
225
  height: var(--theia-icon-size);
227
226
  width: var(--theia-icon-size);
@@ -328,7 +327,8 @@
328
327
  |----------------------------------------------------------------------------*/
329
328
 
330
329
  .lm-TabBar[data-orientation="horizontal"] .lm-TabBar-content-container>.ps__rail-x {
331
- height: var(--theia-private-horizontal-tab-scrollbar-rail-height);
330
+ height: var(--theia-private-horizontal-tab-scrollbar-rail-height) !important;
331
+ background: transparent !important;
332
332
  z-index: 1000;
333
333
  }
334
334
 
@@ -384,9 +384,10 @@
384
384
  /* Due to the scrollbar (`z-index: 1000;`) it has a greater `z-index`. */
385
385
  display: flex;
386
386
  flex-direction: row-reverse;
387
- padding: 4px;
388
- padding-left: 0px;
389
- margin-right: 4px;
387
+ align-items: center;
388
+ justify-content: center;
389
+ padding-inline: var(--theia-ui-padding);
390
+ gap: 2px;
390
391
  }
391
392
 
392
393
  .lm-TabBar-content-container {
@@ -402,7 +403,7 @@
402
403
  display: flex;
403
404
  flex-direction: row;
404
405
  column-gap: 0px;
405
- align-items: centery;
406
+ align-items: center;
406
407
  }
407
408
 
408
409
  .lm-TabBar-toolbar .item>div {
@@ -414,7 +415,7 @@
414
415
  cursor: pointer;
415
416
  }
416
417
 
417
- .lm-TabBar-toolbar :not(.item.enabled) .action-label {
418
+ .lm-TabBar-toolbar > :not(.item.enabled) > .action-label {
418
419
  background: transparent;
419
420
  cursor: default;
420
421
  }
@@ -425,10 +426,10 @@
425
426
  }
426
427
 
427
428
  .lm-TabBar-toolbar .item>div {
428
- line-height: calc(var(--theia-icon-size) + 2px);
429
- height: calc(var(--theia-icon-size) + 2px);
429
+ min-width: var(--theia-icon-size);
430
+ height: var(--theia-icon-size);
431
+ line-height: var(--theia-icon-size);
430
432
  background-repeat: no-repeat;
431
- line-height: 18px;
432
433
  }
433
434
 
434
435
  .lm-TabBar-toolbar .item>div.no-icon {
@@ -492,6 +493,7 @@
492
493
 
493
494
  .lm-TabBar[data-orientation="horizontal"] .lm-TabBar-content {
494
495
  flex-direction: row;
496
+ min-height: var(--theia-horizontal-toolbar-height);
495
497
  }
496
498
 
497
499
  .lm-TabBar[data-orientation="vertical"] .lm-TabBar-content {
@@ -73,14 +73,16 @@
73
73
  .theia-TreeNodeContent {
74
74
  display: flex;
75
75
  align-items: center;
76
- width: calc(100% - var(--theia-scrollbar-rail-width));
76
+ width: 100%;
77
+ padding-right: var(--theia-ui-padding);
78
+ box-sizing: border-box;
77
79
  }
78
80
 
79
81
  .theia-ExpansionToggle {
80
82
  display: flex;
81
83
  justify-content: center;
82
- padding-left: calc(var(--theia-ui-padding) / 2);
83
- padding-right: calc(var(--theia-ui-padding) / 2);
84
+ padding-left: calc(var(--theia-ui-padding) / 3);
85
+ padding-right: calc(var(--theia-ui-padding) / 3);
84
86
  min-width: var(--theia-icon-size);
85
87
  min-height: var(--theia-icon-size);
86
88
  }
@@ -15,7 +15,7 @@
15
15
  ********************************************************************************/
16
16
 
17
17
  :root {
18
- --theia-view-container-title-height: var(--theia-content-line-height);
18
+ --theia-view-container-title-height: 24px;
19
19
  --theia-view-container-content-height: calc(100% - var(--theia-view-container-title-height));
20
20
  }
21
21
 
@@ -82,10 +82,6 @@
82
82
  box-shadow: none;
83
83
  }
84
84
 
85
- .theia-view-container-part-header .theia-ExpansionToggle {
86
- padding-left: 4px;
87
- }
88
-
89
85
  .theia-view-container>.lm-SplitPanel[data-orientation="horizontal"] .part>.theia-header .theia-ExpansionToggle::before {
90
86
  display: none;
91
87
  padding-left: 0px;
@@ -114,7 +110,7 @@
114
110
  }
115
111
 
116
112
  .theia-view-container-part-header .notification-count-container {
117
- margin-right: 12px;
113
+ margin-right: var(--theia-ui-padding);
118
114
  }
119
115
 
120
116
  .theia-view-container .part>.body {
@@ -156,7 +152,7 @@
156
152
  .lm-TabBar-toolbar.theia-view-container-part-title {
157
153
  overflow: visible !important;
158
154
  padding: 0px;
159
- padding-right: calc(var(--theia-ui-padding) * 2 / 3);
155
+ padding-right: var(--theia-ui-padding);
160
156
  }
161
157
 
162
158
  .theia-view-container-part-title {
@@ -21,7 +21,8 @@ import { Key, KeyCode, KeyModifier } from '../keyboard/keys';
21
21
  import { ContextMenuRenderer } from '../context-menu-renderer';
22
22
  import { StatefulWidget } from '../shell';
23
23
  import {
24
- EXPANSION_TOGGLE_CLASS, SELECTED_CLASS, COLLAPSED_CLASS, FOCUS_CLASS, BUSY_CLASS, CODICON_TREE_ITEM_CLASSES, CODICON_LOADING_CLASSES, Widget, UnsafeWidgetUtilities
24
+ EXPANSION_TOGGLE_CLASS, SELECTED_CLASS, COLLAPSED_CLASS, FOCUS_CLASS, BUSY_CLASS, CODICON_TREE_ITEM_CLASSES, CODICON_LOADING_CLASSES, Widget, UnsafeWidgetUtilities,
25
+ addEventListener
25
26
  } from '../widgets';
26
27
  import { TreeNode, CompositeTreeNode } from './tree';
27
28
  import { TreeModel } from './tree-model';
@@ -81,6 +82,8 @@ export interface TreeScrollEvent {
81
82
  export interface TreeScrollState {
82
83
  readonly scrollTop: number;
83
84
  readonly isAtBottom: boolean;
85
+ readonly scrollHeight?: number;
86
+ readonly clientHeight?: number;
84
87
  }
85
88
 
86
89
  export const TreeProps = Symbol('TreeProps');
@@ -313,31 +316,9 @@ export class TreeWidget extends ReactWidget implements StatefulWidget {
313
316
  this.updateDecorations();
314
317
  });
315
318
  if (this.props.globalSelection) {
316
- this.toDispose.pushAll([
317
- this.model.onSelectionChanged(() => {
318
- if (this.node.contains(document.activeElement)) {
319
- this.updateGlobalSelection();
320
- }
321
- }),
322
- this.focusService.onDidChangeFocus(focus => {
323
- if (focus && this.node.contains(document.activeElement) && this.model.selectedNodes[0] !== focus && this.model.selectedNodes.includes(focus)) {
324
- this.updateGlobalSelection();
325
- }
326
- }),
327
- Disposable.create(() => {
328
- const selection = this.selectionService.selection;
329
- if (TreeWidgetSelection.isSource(selection, this)) {
330
- this.selectionService.selection = undefined;
331
- }
332
- })
333
- ]);
334
-
335
- this.node.addEventListener('focusin', e => {
336
- if (this.model.selectedNodes.length && (!this.selectionService.selection || !TreeWidgetSelection.isSource(this.selectionService.selection, this))) {
337
- this.updateGlobalSelection();
338
- }
339
- });
319
+ this.registerGlobalSelectionHandlers();
340
320
  }
321
+
341
322
  this.toDispose.push(this.corePreferences.onPreferenceChanged(preference => {
342
323
  if (preference.preferenceName === 'workbench.tree.renderIndentGuides') {
343
324
  this.update();
@@ -345,6 +326,41 @@ export class TreeWidget extends ReactWidget implements StatefulWidget {
345
326
  }));
346
327
  }
347
328
 
329
+ protected registerGlobalSelectionHandlers(): void {
330
+ this.model.onSelectionChanged(this.handleGlobalSelectionOnModelSelectionChange, this, this.toDispose);
331
+ this.focusService.onDidChangeFocus(this.handleGlobalSelectionOnFocusServiceFocusChange, this, this.toDispose);
332
+ this.toDispose.push(addEventListener(this.node, 'focusin', this.handleGlobalSelectionOnFocusIn.bind(this)));
333
+ this.toDispose.push(Disposable.create(this.handleGlobalSelectionOnDisposal.bind(this)));
334
+ }
335
+
336
+ protected handleGlobalSelectionOnModelSelectionChange(): void {
337
+ if (this.shouldUpdateGlobalSelection()) {
338
+ this.updateGlobalSelection();
339
+ }
340
+ }
341
+
342
+ protected handleGlobalSelectionOnFocusServiceFocusChange(focus: SelectableTreeNode | undefined): void {
343
+ if (focus && this.shouldUpdateGlobalSelection() && this.model.selectedNodes[0] !== focus && this.model.selectedNodes.includes(focus)) {
344
+ this.updateGlobalSelection();
345
+ }
346
+ }
347
+
348
+ protected handleGlobalSelectionOnFocusIn(): void {
349
+ if (this.model.selectedNodes.length && (!this.selectionService.selection || !TreeWidgetSelection.isSource(this.selectionService.selection, this))) {
350
+ this.updateGlobalSelection();
351
+ }
352
+ }
353
+
354
+ protected handleGlobalSelectionOnDisposal(): void {
355
+ if (TreeWidgetSelection.isSource(this.selectionService.selection, this)) {
356
+ this.selectionService.selection = undefined;
357
+ }
358
+ }
359
+
360
+ protected shouldUpdateGlobalSelection(): boolean {
361
+ return this.node.contains(document.activeElement) || TreeWidgetSelection.isSource(this.selectionService.selection, this);
362
+ }
363
+
348
364
  /**
349
365
  * Update the global selection for the tree.
350
366
  */
@@ -1643,7 +1659,7 @@ export namespace TreeWidget {
1643
1659
  }
1644
1660
  export class View extends React.Component<ViewProps> {
1645
1661
  list: VirtuosoHandle | undefined;
1646
- private lastScrollState: TreeScrollState = { scrollTop: 0, isAtBottom: true };
1662
+ private lastScrollState: TreeScrollState = { scrollTop: 0, isAtBottom: true, scrollHeight: 0, clientHeight: 0 };
1647
1663
 
1648
1664
  override render(): React.ReactNode {
1649
1665
  const { rows, width, height, scrollToRow, renderNodeRow, onScrollEmitter, ...other } = this.props;
@@ -1665,9 +1681,16 @@ export namespace TreeWidget {
1665
1681
  const isAtBottom = scrollHeight - scrollTop - clientHeight <= SCROLL_BOTTOM_THRESHOLD;
1666
1682
 
1667
1683
  // Store scroll state before firing the event to prevent jitter during inference and scrolling
1668
- this.lastScrollState = { scrollTop, isAtBottom };
1684
+ this.lastScrollState = { scrollTop, isAtBottom, scrollHeight, clientHeight };
1669
1685
  onScrollEmitter?.fire({ scrollTop, scrollLeft: e.target.scrollLeft || 0 });
1670
1686
  }}
1687
+ atBottomStateChange={(atBottom: boolean) => {
1688
+ this.lastScrollState = {
1689
+ ...this.lastScrollState,
1690
+ isAtBottom: atBottom
1691
+ };
1692
+ }}
1693
+ atBottomThreshold={SCROLL_BOTTOM_THRESHOLD}
1671
1694
  totalCount={rows.length}
1672
1695
  itemContent={index => renderNodeRow(rows[index])}
1673
1696
  width={width}
@@ -43,9 +43,9 @@ export class AlertMessage extends React.Component<AlertMessageProps> {
43
43
 
44
44
  override render(): React.ReactNode {
45
45
  return <div className='theia-alert-message-container'>
46
- <div className={`theia-${this.props.type.toLowerCase()}-alert`}>
46
+ <div className={`theia-alert theia-${this.props.type.toLowerCase()}-alert`}>
47
47
  <div className='theia-message-header'>
48
- <i className={AlertMessageIcon[this.props.type]}></i>&nbsp;
48
+ <i className={AlertMessageIcon[this.props.type]}></i>
49
49
  {this.props.header}
50
50
  </div>
51
51
  <div className='theia-message-content'>{this.props.children}</div>
@@ -34,6 +34,8 @@ export interface SelectOption {
34
34
  }
35
35
 
36
36
  export interface SelectComponentProps {
37
+ id?: string
38
+ className?: string
37
39
  options: readonly SelectOption[]
38
40
  defaultValue?: string | number
39
41
  onChange?: (option: SelectOption, index: number) => void,
@@ -193,10 +195,11 @@ export class SelectComponent extends React.Component<SelectComponentProps, Selec
193
195
  const selectedItemLabel = options[selected]?.label ?? options[selected]?.value;
194
196
  return <>
195
197
  <div
198
+ id={this.props.id}
196
199
  key="select-component"
197
200
  ref={this.fieldRef}
198
201
  tabIndex={0}
199
- className="theia-select-component"
202
+ className={`theia-select-component${this.props.className ? ` ${this.props.className}` : ''}`}
200
203
  onClick={e => this.handleClickEvent(e)}
201
204
  onBlur={
202
205
  () => {
@@ -450,11 +450,17 @@ export class ElectronMainApplication {
450
450
  const windowState = previousWindowState?.screenLayout === this.getCurrentScreenLayout()
451
451
  ? previousWindowState
452
452
  : this.getDefaultTheiaWindowOptions();
453
- return {
453
+ const result = {
454
454
  frame: this.useNativeWindowFrame,
455
455
  ...this.getDefaultOptions(),
456
456
  ...windowState
457
457
  };
458
+
459
+ result.webPreferences = {
460
+ ...result.webPreferences,
461
+ preload: path.resolve(this.globals.THEIA_APP_PROJECT_PATH, 'lib', 'frontend', 'preload.js').toString()
462
+ };
463
+ return result;
458
464
  }
459
465
 
460
466
  protected avoidOverlap(options: TheiaBrowserWindowOptions): TheiaBrowserWindowOptions {
@@ -489,7 +495,7 @@ export class ElectronMainApplication {
489
495
  // Issue: https://github.com/eclipse-theia/theia/issues/8577
490
496
  nodeIntegrationInWorker: false,
491
497
  backgroundThrottling: false,
492
- preload: path.resolve(this.globals.THEIA_APP_PROJECT_PATH, 'lib', 'frontend', 'preload.js').toString()
498
+ enableDeprecatedPaste: true
493
499
  },
494
500
  ...this.config.electron?.windowOptions || {},
495
501
  };
@@ -565,13 +571,18 @@ export class ElectronMainApplication {
565
571
  }
566
572
 
567
573
  protected getDefaultTheiaWindowOptions(): TheiaBrowserWindowOptions {
568
- return {
574
+ const result = {
569
575
  frame: this.useNativeWindowFrame,
570
576
  isFullScreen: false,
571
577
  isMaximized: false,
572
578
  ...this.getDefaultTheiaWindowBounds(),
573
- ...this.getDefaultOptions()
579
+ ...this.getDefaultOptions(),
580
+ };
581
+ result.webPreferences = {
582
+ ...result.webPreferences || {},
583
+ preload: path.resolve(this.globals.THEIA_APP_PROJECT_PATH, 'lib', 'frontend', 'preload.js').toString()
574
584
  };
585
+ return result;
575
586
  }
576
587
 
577
588
  protected getDefaultTheiaSecondaryWindowBounds(): TheiaBrowserWindowOptions {
@@ -780,16 +791,20 @@ export class ElectronMainApplication {
780
791
  webContents.setWindowOpenHandler(details => {
781
792
  // if it's a secondary window, allow it to open
782
793
  if (new URI(details.url).path.fsPath() === new Path(this.globals.THEIA_SECONDARY_WINDOW_HTML_PATH).fsPath()) {
783
- const { minWidth, minHeight } = this.getDefaultOptions();
794
+ const defaultOptions = this.getDefaultOptions();
784
795
  const options: BrowserWindowConstructorOptions = {
785
796
  ...this.getDefaultTheiaSecondaryWindowBounds(),
786
797
  // We always need the native window frame for now because the secondary window does not have Theia's title bar by default.
787
798
  // In 'custom' title bar mode this would leave the window without any window controls (close, min, max)
788
799
  // TODO set to this.useNativeWindowFrame when secondary windows support a custom title bar.
789
800
  frame: true,
790
- minWidth,
791
- minHeight
801
+ minWidth: defaultOptions.minWidth,
802
+ minHeight: defaultOptions.minHeight,
803
+ webPreferences: {
804
+ enableDeprecatedPaste: defaultOptions.webPreferences?.enableDeprecatedPaste
805
+ }
792
806
  };
807
+
793
808
  if (!this.useNativeWindowFrame) {
794
809
  // If the main window does not have a native window frame, do not show an icon in the secondary window's native title bar.
795
810
  // The data url is a 1x1 transparent png