Skip to content

Commit cee979b

Browse files
sdirixtsmaeder
andauthored
feat: migrate from PhosphorJS to Lumino (#14320)
Migrate from the deprecated @phosphor packages to the actively maintained @Lumino fork across the entire codebase. - Replace all @phosphor package imports with @Lumino equivalents - Share Lumino packages instead of PhosphorJS packages - Update CSS selectors from .p- to .lm- class prefixes - Adapt code to Lumino's API changes (e.g. using iconClass instead of class in commands) - Adapt code to Lumino's behavior and CSS changes (e.g. empty menu behavior and focus CSS) - Add Lumino patch for secondary window support - Introduce a testing package to setup tests for Lumino codebase Adopters will need to update their imports to use @Lumino instead, update any custom CSS selectors and potentially adapt their code base. Contributed on behalf of STMicroelectronics Co-authored-by: Thomas Mäder <[email protected]>
1 parent f29a721 commit cee979b

File tree

168 files changed

+1339
-941
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

168 files changed

+1339
-941
lines changed

CHANGELOG.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44

55
- [Previous Changelogs](https://github.com/eclipse-theia/theia/tree/master/doc/changelogs/)
66

7-
## 1.60.0
7+
## 1.60.0 - not yet released
88

99
<a name="breaking_changes_1.60.0">[Breaking Changes:](#breaking_changes_1.60.0)</a>
1010

1111
- [core] fixed version `@types/express` to `^4.17.21` and `@types/express-serve-static-core` to `5.0.4`. This might be required for adopters as well if they run into typing issues. [#15147](https://github.com/eclipse-theia/theia/pull/15147)
12+
- [core] migration from deprecated `phosphorJs` to actively maintained fork `Lumino` [#14320](https://github.com/eclipse-theia/theia/pull/14320) - Contributed on behalf of STMicroelectronics
13+
Adopters importing `@phosphor` packages now need to import from `@lumino`. CSS selectors refering to `.p-` classes now need to refer to `.lm-` classes. There are also minor code adaptations, for example now using `iconClass` instead of `icon` in Lumino commands.
1214

1315
## 1.59.0 - 02/27/2025
1416

configs/mocharc.yml

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
require:
22
- 'ignore-styles'
33
- 'reflect-metadata/Reflect'
4+
- '@theia/test-setup'
45
reporter: 'spec'
56
watch-files:
67
- '**/*.js'

dev-packages/cli/patches/@lumino+widgets+2.5.0.patch

+449
Large diffs are not rendered by default.

dev-packages/cli/patches/@phosphor+widgets+1.9.3.patch

-157
This file was deleted.

dev-packages/cli/src/run-test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export default async function runTest(options: TestOptions): Promise<void> {
4949
// When launching in non-headless mode (with a UI and dev-tools open), make sure
5050
// the app has focus, to avoid failures of tests that query the UI's state.
5151
if (launch && launch.devtools) {
52-
promises.push(testPage.waitForSelector('#theia-app-shell.p-Widget.theia-ApplicationShell')
52+
promises.push(testPage.waitForSelector('#theia-app-shell.lm-Widget.theia-ApplicationShell')
5353
.then(e => {
5454
// eslint-disable-next-line no-null/no-null
5555
if (e !== null) {
+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<div align='center'>
2+
3+
<br />
4+
5+
<img src='https://raw.githubusercontent.com/eclipse-theia/theia/master/logo/theia.svg?sanitize=true' alt='theia-ext-logo' width='100px' />
6+
7+
<h2>ECLIPSE THEIA - TEST SETUP</h2>
8+
9+
<hr />
10+
11+
</div>
12+
13+
## Description
14+
15+
The `@theia/test-setup` contributes a setup script for mocha executed tests in Theia.
16+
This setup script is executed before any test file is loaded or compiled.
17+
This is for example useful for globals which must exist before dependencies are loaded.
18+
19+
## Additional Information
20+
21+
- [Theia - GitHub](https://github.com/eclipse-theia/theia)
22+
- [Theia - Website](https://theia-ide.org/)
23+
24+
## License
25+
26+
- [Eclipse Public License 2.0](http://www.eclipse.org/legal/epl-2.0/)
27+
- [一 (Secondary) GNU General Public License, version 2 with the GNU Classpath Exception](https://projects.eclipse.org/license/secondary-gpl-2.0-cp)
28+
29+
## Trademark
30+
31+
"Theia" is a trademark of the Eclipse Foundation
32+
https://www.eclipse.org/theia
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"private": true,
3+
"name": "@theia/test-setup",
4+
"version": "1.59.0",
5+
"description": "Custom setup for mocha tests",
6+
"main": "test-setup.js"
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
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+
// Mock DragEvent as '@lumino/dragdrop' already requires it at require time
18+
global.DragEvent = class DragEvent { };

examples/api-samples/src/browser/menu/sample-browser-menu-module.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
// *****************************************************************************
1616

1717
import { injectable, ContainerModule } from '@theia/core/shared/inversify';
18-
import { Menu as MenuWidget } from '@theia/core/shared/@phosphor/widgets';
18+
import { Menu as MenuWidget } from '@theia/core/shared/@lumino/widgets';
1919
import { Disposable } from '@theia/core/lib/common/disposable';
2020
import { MenuNode, CompoundMenuNode, MenuPath } from '@theia/core/lib/common/menu';
2121
import { BrowserMainMenuFactory, MenuCommandRegistry, DynamicMenuWidget, BrowserMenuOptions } from '@theia/core/lib/browser/menu/browser-menu-plugin';
@@ -74,7 +74,7 @@ class SampleMenuCommandRegistry extends MenuCommandRegistry {
7474
return this.addCommand(id, {
7575
execute: () => { /* NOOP */ },
7676
label: menu.label,
77-
icon: menu.icon,
77+
iconClass: menu.icon,
7878
isEnabled: () => false,
7979
isVisible: () => true
8080
});

examples/api-samples/src/browser/monaco-editor-preferences/monaco-editor-preference-extractor.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import { inject, injectable, interfaces } from '@theia/core/shared/inversify';
2929
import { FileService } from '@theia/filesystem/lib/browser/file-service';
3030
import { WorkspaceService } from '@theia/workspace/lib/browser';
3131
import { PreferenceItem, PreferenceValidationService } from '@theia/core/lib/browser';
32-
import { JSONValue } from '@theia/core/shared/@phosphor/coreutils';
32+
import { JSONValue } from '@theia/core/shared/@lumino/coreutils';
3333
import { JsonType } from '@theia/core/lib/common/json-schema';
3434
import { editorOptionsRegistry } from '@theia/monaco-editor-core/esm/vs/editor/common/config/editorOptions';
3535
import { MonacoEditorProvider } from '@theia/monaco/lib/browser/monaco-editor-provider';

examples/playwright/src/theia-app.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ export class TheiaApp {
176176
}
177177

178178
protected async visibleTabIds(): Promise<string[]> {
179-
const tabs = await this.page.$$('.p-TabBar-tab');
179+
const tabs = await this.page.$$('.lm-TabBar-tab');
180180
const tabIds = (await Promise.all(tabs.map(tab => tab.getAttribute('id')))).filter(id => !!id);
181181
return tabIds as string[];
182182
}

examples/playwright/src/theia-main-menu.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { TheiaPageObject } from './theia-page-object';
2121
import { normalizeId, toTextContentArray } from './util';
2222

2323
export class TheiaMainMenu extends TheiaMenu {
24-
override selector = '.p-Menu.p-MenuBar-menu';
24+
override selector = '.lm-Menu.lm-MenuBar-menu';
2525
}
2626

2727
export class TheiaMenuBar extends TheiaPageObject {
@@ -48,7 +48,7 @@ export class TheiaMenuBar extends TheiaPageObject {
4848
}
4949

5050
protected menuBarItemSelector(label = ''): string {
51-
return `${normalizeId('#theia:menubar')} .p-MenuBar-itemLabel >> text=${label}`;
51+
return `${normalizeId('#theia:menubar')} .lm-MenuBar-itemLabel >> text=${label}`;
5252
}
5353

5454
}

examples/playwright/src/theia-menu-item.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,15 @@ export class TheiaMenuItem {
2323
constructor(protected element: ElementHandle<SVGElement | HTMLElement>) { }
2424

2525
protected labelElementHandle(): Promise<ElementHandle<SVGElement | HTMLElement>> {
26-
return this.element.waitForSelector('.p-Menu-itemLabel');
26+
return this.element.waitForSelector('.lm-Menu-itemLabel');
2727
}
2828

2929
protected shortCutElementHandle(): Promise<ElementHandle<SVGElement | HTMLElement>> {
30-
return this.element.waitForSelector('.p-Menu-itemShortcut');
30+
return this.element.waitForSelector('.lm-Menu-itemShortcut');
3131
}
3232

3333
protected isHidden(): Promise<boolean> {
34-
return elementContainsClass(this.element, 'p-mod-collapsed');
34+
return elementContainsClass(this.element, 'lm-mod-collapsed');
3535
}
3636

3737
async label(): Promise<string | undefined> {
@@ -60,11 +60,11 @@ export class TheiaMenuItem {
6060
if (classAttribute === undefined || classAttribute === null) {
6161
return false;
6262
}
63-
return !classAttribute.includes('p-mod-disabled') && !classAttribute.includes('p-mod-collapsed');
63+
return !classAttribute.includes('lm-mod-disabled') && !classAttribute.includes('lm-mod-collapsed');
6464
}
6565

6666
async click(): Promise<void> {
67-
return this.element.waitForSelector('.p-Menu-itemLabel')
67+
return this.element.waitForSelector('.lm-Menu-itemLabel')
6868
.then(labelElement => labelElement.click({ position: { x: 10, y: 10 } }));
6969
}
7070

examples/playwright/src/theia-menu.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import { isDefined } from './util';
2222

2323
export class TheiaMenu extends TheiaPageObject {
2424

25-
selector = '.p-Menu';
25+
selector = '.lm-Menu';
2626

2727
protected async menuElementHandle(): Promise<ElementHandle<SVGElement | HTMLElement> | null> {
2828
return this.page.$(this.selector);
@@ -50,7 +50,7 @@ export class TheiaMenu extends TheiaPageObject {
5050
if (!menuHandle) {
5151
return [];
5252
}
53-
const items = await menuHandle.$$('.p-Menu-content .p-Menu-item');
53+
const items = await menuHandle.$$('.lm-Menu-content .lm-Menu-item');
5454
return items.map(element => new TheiaMenuItem(element));
5555
}
5656

@@ -84,7 +84,7 @@ export class TheiaMenu extends TheiaPageObject {
8484
}
8585

8686
protected menuItemSelector(label = ''): string {
87-
return `.p-Menu-content .p-Menu-itemLabel >> text=${label}`;
87+
return `.lm-Menu-content .lm-Menu-itemLabel >> text=${label}`;
8888
}
8989

9090
async visibleMenuItems(): Promise<string[]> {

examples/playwright/src/theia-output-view.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export class TheiaOutputView extends TheiaView {
4747
await this.activate();
4848
const channel = new TheiaOutputViewChannel(
4949
{
50-
viewSelector: 'div.p-Widget.theia-editor.p-DockPanel-widget > div.monaco-editor',
50+
viewSelector: 'div.lm-Widget.theia-editor.lm-DockPanel-widget > div.monaco-editor',
5151
dataUri: normalizeId(`output:/${encodeURIComponent(outputChannelName)}`),
5252
channelName: outputChannelName
5353
},

examples/playwright/src/theia-preference-view.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ export class TheiaPreferenceView extends TheiaView {
106106
}
107107

108108
protected getScopeSelector(scope: TheiaPreferenceScope): string {
109-
return `li.preferences-scope-tab div.p-TabBar-tabLabel:has-text("${scope}")`;
109+
return `li.preferences-scope-tab div.lm-TabBar-tabLabel:has-text("${scope}")`;
110110
}
111111

112112
async openPreferenceScope(scope: TheiaPreferenceScope): Promise<void> {

examples/playwright/src/theia-toolbar.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { TheiaPageObject } from './theia-page-object';
1919
import { TheiaToolbarItem } from './theia-toolbar-item';
2020

2121
export class TheiaToolbar extends TheiaPageObject {
22-
selector = 'div#main-toolbar.p-TabBar-toolbar';
22+
selector = 'div#main-toolbar.lm-TabBar-toolbar';
2323

2424
protected async toolbarElementHandle(): Promise<ElementHandle<SVGElement | HTMLElement> | null> {
2525
return this.page.$(this.selector);

0 commit comments

Comments
 (0)