diff --git a/CHANGELOG.md b/CHANGELOG.md
index fbb6bf162b8f9..112cd00b621ca 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,13 @@
# Change Log
+
+## v1.12.0
+
+- [filesystem] add text input and navigate up icon to file dialog [#8748](https://github.com/eclipse-theia/theia/pull/8748)
+
+[Breaking Changes:](#breaking_changes_1.12.0)
+
+- [filesystem] `FileDialog` and `LocationListRenderer` now require `FileService` to be passed into constructor for text-based file dialog navigation in browser [#8748](https://github.com/eclipse-theia/theia/pull/8748)
+
## v1.11.0 - 2/25/2021
- [api-samples] added example to echo the currently supported vscode API version [#8191](https://github.com/eclipse-theia/theia/pull/8191)
@@ -40,7 +49,6 @@
- [task] updated logic to activate corresponding terminal when using the `show running tasks` action [#9016](https://github.com/eclipse-theia/theia/pull/9016)
- [vsx-registry] added API compatibility handling when installing extensions through the 'extensions-view' [#8191](https://github.com/eclipse-theia/theia/pull/8191)
-
[Breaking Changes:](#breaking_changes_1.11.0)
- [core] updated `SearchBox.input` field type from `HTMLInputElement` to `HTMLSpanElement` [#9005](https://github.com/eclipse-theia/theia/pull/9005)
diff --git a/packages/core/src/browser/style/tabs.css b/packages/core/src/browser/style/tabs.css
index 80e5c437aa031..112fa4c685405 100644
--- a/packages/core/src/browser/style/tabs.css
+++ b/packages/core/src/browser/style/tabs.css
@@ -8,6 +8,7 @@
--theia-private-horizontal-tab-scrollbar-rail-height: 7px;
--theia-private-horizontal-tab-scrollbar-height: 5px;
--theia-tabbar-toolbar-z-index: 1001;
+ --theia-toolbar-active-transform-scale: 1.272019649;
}
/*-----------------------------------------------------------------------------
@@ -352,7 +353,7 @@ body.theia-editor-highlightModifiedTabs
}
.p-TabBar-toolbar .item.enabled.active {
- transform: scale(1.272019649);
+ transform: scale(var(--theia-toolbar-active-transform-scale));
}
.p-TabBar-toolbar .item.toggled {
diff --git a/packages/filesystem/src/browser/file-dialog/file-dialog-model.ts b/packages/filesystem/src/browser/file-dialog/file-dialog-model.ts
index 42bcfd39061e1..29f57467b19cc 100644
--- a/packages/filesystem/src/browser/file-dialog/file-dialog-model.ts
+++ b/packages/filesystem/src/browser/file-dialog/file-dialog-model.ts
@@ -88,4 +88,9 @@ export class FileDialogModel extends FileTreeModel {
private isFileStatNodeSelectable(node: FileStatNode): boolean {
return !(!node.fileStat.isDirectory && this._disableFileSelection);
}
+
+ canNavigateUpward(): boolean {
+ const treeRoot = this.tree.root;
+ return FileStatNode.is(treeRoot) && !treeRoot.uri.path.isRoot;
+ }
}
diff --git a/packages/filesystem/src/browser/file-dialog/file-dialog.ts b/packages/filesystem/src/browser/file-dialog/file-dialog.ts
index fac4cac3bceb9..72935ef80371d 100644
--- a/packages/filesystem/src/browser/file-dialog/file-dialog.ts
+++ b/packages/filesystem/src/browser/file-dialog/file-dialog.ts
@@ -26,6 +26,7 @@ import { FileDialogWidget } from './file-dialog-widget';
import { FileDialogTreeFiltersRenderer, FileDialogTreeFilters } from './file-dialog-tree-filters-renderer';
import URI from '@theia/core/lib/common/uri';
import { Panel } from '@phosphor/widgets';
+import { FileService } from '../file-service';
export const OpenFileDialogFactory = Symbol('OpenFileDialogFactory');
export interface OpenFileDialogFactory {
@@ -43,6 +44,7 @@ export const NAVIGATION_PANEL_CLASS = 'theia-NavigationPanel';
export const NAVIGATION_BACK_CLASS = 'theia-NavigationBack';
export const NAVIGATION_FORWARD_CLASS = 'theia-NavigationForward';
export const NAVIGATION_HOME_CLASS = 'theia-NavigationHome';
+export const NAVIGATION_UP_CLASS = 'theia-NavigationUp';
export const NAVIGATION_LOCATION_LIST_PANEL_CLASS = 'theia-LocationListPanel';
export const FILTERS_PANEL_CLASS = 'theia-FiltersPanel';
@@ -54,6 +56,7 @@ export const FILENAME_LABEL_CLASS = 'theia-FileNameLabel';
export const FILENAME_TEXTFIELD_CLASS = 'theia-FileNameTextField';
export const CONTROL_PANEL_CLASS = 'theia-ControlPanel';
+export const TOOLBAR_ITEM_TRANSFORM_TIMEOUT = 100;
export class FileDialogProps extends DialogProps {
@@ -116,13 +119,15 @@ export abstract class FileDialog extends AbstractDialog {
protected readonly back: HTMLSpanElement;
protected readonly forward: HTMLSpanElement;
protected readonly home: HTMLSpanElement;
+ protected readonly up: HTMLSpanElement;
protected readonly locationListRenderer: LocationListRenderer;
protected readonly treeFiltersRenderer: FileDialogTreeFiltersRenderer | undefined;
protected readonly treePanel: Panel;
constructor(
@inject(FileDialogProps) readonly props: FileDialogProps,
- @inject(FileDialogWidget) readonly widget: FileDialogWidget
+ @inject(FileDialogWidget) readonly widget: FileDialogWidget,
+ @inject(FileService) readonly fileService: FileService
) {
super(props);
this.treePanel = new Panel();
@@ -145,8 +150,13 @@ export abstract class FileDialog extends AbstractDialog {
navigationPanel.appendChild(this.home = createIconButton('fa', 'fa-home'));
this.home.classList.add(NAVIGATION_HOME_CLASS);
this.home.title = 'Go To Initial Location';
+ navigationPanel.appendChild(this.up = createIconButton('fa', 'fa-level-up'));
+ this.up.classList.add(NAVIGATION_UP_CLASS);
+ this.up.title = 'Navigate Up One Directory';
- this.locationListRenderer = this.createLocationListRenderer();
+ const locationListRendererHost = document.createElement('div');
+ this.locationListRenderer = this.createLocationListRenderer(locationListRendererHost);
+ this.toDispose.push(this.locationListRenderer);
this.locationListRenderer.host.classList.add(NAVIGATION_LOCATION_LIST_PANEL_CLASS);
navigationPanel.appendChild(this.locationListRenderer.host);
@@ -157,8 +167,8 @@ export abstract class FileDialog extends AbstractDialog {
return this.widget.model;
}
- protected createLocationListRenderer(): LocationListRenderer {
- return new LocationListRenderer(this.model);
+ protected createLocationListRenderer(host?: HTMLElement): LocationListRenderer {
+ return new LocationListRenderer(this.model, this.fileService, host);
}
protected createFileTreeFiltersRenderer(): FileDialogTreeFiltersRenderer | undefined {
@@ -176,6 +186,7 @@ export abstract class FileDialog extends AbstractDialog {
setEnabled(this.home, !!this.model.initialLocation
&& !!this.model.location
&& this.model.initialLocation.toString() !== this.model.location.toString());
+ setEnabled(this.up, this.model.canNavigateUpward());
this.locationListRenderer.render();
if (this.treeFiltersRenderer) {
@@ -185,6 +196,28 @@ export abstract class FileDialog extends AbstractDialog {
this.widget.update();
}
+ protected handleEnter(event: KeyboardEvent): boolean | void {
+ if (event.target instanceof HTMLTextAreaElement || this.targetIsDirectoryInput(event.target) || this.targetIsInputToggle(event.target)) {
+ return false;
+ }
+ this.accept();
+ }
+
+ protected handleEscape(event: KeyboardEvent): boolean | void {
+ if (event.target instanceof HTMLTextAreaElement || this.targetIsDirectoryInput(event.target)) {
+ return false;
+ }
+ this.close();
+ }
+
+ protected targetIsDirectoryInput(target: EventTarget | null): boolean {
+ return target instanceof HTMLInputElement && target.classList.contains(LocationListRenderer.Styles.LOCATION_TEXT_INPUT_CLASS);
+ }
+
+ protected targetIsInputToggle(target: EventTarget | null): boolean {
+ return target instanceof HTMLSpanElement && target.classList.contains(LocationListRenderer.Styles.LOCATION_INPUT_TOGGLE_CLASS);
+ }
+
protected appendFiltersPanel(): void {
if (this.treeFiltersRenderer) {
const filtersPanel = document.createElement('div');
@@ -216,16 +249,36 @@ export abstract class FileDialog extends AbstractDialog {
this.appendCloseButton('Cancel');
this.appendAcceptButton(this.getAcceptButtonLabel());
- this.addKeyListener(this.back, Key.ENTER, () => this.model.navigateBackward(), 'click');
- this.addKeyListener(this.forward, Key.ENTER, () => this.model.navigateForward(), 'click');
+ this.addKeyListener(this.back, Key.ENTER, () => {
+ this.addTransformEffectToIcon(this.back);
+ this.model.navigateBackward();
+ }, 'click');
+
+ this.addKeyListener(this.forward, Key.ENTER, () => {
+ this.addTransformEffectToIcon(this.forward);
+ this.model.navigateForward();
+ }, 'click');
this.addKeyListener(this.home, Key.ENTER, () => {
+ this.addTransformEffectToIcon(this.home);
if (this.model.initialLocation) {
this.model.location = this.model.initialLocation;
}
}, 'click');
+ this.addKeyListener(this.up, Key.ENTER, () => {
+ this.addTransformEffectToIcon(this.up);
+ if (this.model.location) {
+ this.model.location = this.model.location.parent;
+ }
+ }, 'click');
super.onAfterAttach(msg);
}
+ protected addTransformEffectToIcon(element: HTMLSpanElement): void {
+ const icon = element.getElementsByTagName('i')[0];
+ icon.classList.add('active');
+ setTimeout(() => icon.classList.remove('active'), TOOLBAR_ITEM_TRANSFORM_TIMEOUT);
+ }
+
protected abstract getAcceptButtonLabel(): string;
protected onActivateRequest(msg: Message): void {
@@ -239,9 +292,10 @@ export class OpenFileDialog extends FileDialog> {
constructor(
@inject(OpenFileDialogProps) readonly props: OpenFileDialogProps,
- @inject(FileDialogWidget) readonly widget: FileDialogWidget
+ @inject(FileDialogWidget) readonly widget: FileDialogWidget,
+ @inject(FileService) readonly fileService: FileService
) {
- super(props, widget);
+ super(props, widget, fileService);
if (props.canSelectFiles !== undefined) {
this.widget.disableFileSelection = !props.canSelectFiles;
}
@@ -288,9 +342,10 @@ export class SaveFileDialog extends FileDialog {
constructor(
@inject(SaveFileDialogProps) readonly props: SaveFileDialogProps,
- @inject(FileDialogWidget) readonly widget: FileDialogWidget
+ @inject(FileDialogWidget) readonly widget: FileDialogWidget,
+ @inject(FileService) readonly fileService: FileService
) {
- super(props, widget);
+ super(props, widget, fileService);
widget.addClass(SAVE_DIALOG_CLASS);
}
diff --git a/packages/filesystem/src/browser/file-tree/file-tree-model.ts b/packages/filesystem/src/browser/file-tree/file-tree-model.ts
index 1f8440e41157d..b4dd92bf41b3a 100644
--- a/packages/filesystem/src/browser/file-tree/file-tree-model.ts
+++ b/packages/filesystem/src/browser/file-tree/file-tree-model.ts
@@ -61,6 +61,8 @@ export class FileTreeModel extends TreeModelImpl implements LocationService {
const node = DirNode.createRoot(fileStat);
this.navigateTo(node);
}
+ }).catch(() => {
+ // no-op, allow failures for file dialog text input
});
} else {
this.navigateTo(undefined);
diff --git a/packages/filesystem/src/browser/location/location-renderer.tsx b/packages/filesystem/src/browser/location/location-renderer.tsx
index 1ae65e21ac259..1aa8690c31e08 100644
--- a/packages/filesystem/src/browser/location/location-renderer.tsx
+++ b/packages/filesystem/src/browser/location/location-renderer.tsx
@@ -18,13 +18,71 @@ import URI from '@theia/core/lib/common/uri';
import { LocationService } from './location-service';
import { ReactRenderer } from '@theia/core/lib/browser/widgets/react-renderer';
import * as React from 'react';
+import * as ReactDOM from 'react-dom';
+import { FileService } from '../file-service';
+import { DisposableCollection, Emitter } from '@theia/core/lib/common';
+interface AutoSuggestDataEvent {
+ parent: string;
+ children: string[];
+}
+
+class ResolvedDirectoryCache {
+ protected pendingResolvedDirectories = new Map>();
+ protected cachedDirectories = new Map();
+
+ protected directoryResolvedEmitter = new Emitter();
+ readonly onDirectoryDidResolve = this.directoryResolvedEmitter.event;
+
+ constructor(protected readonly fileService: FileService) { }
+
+ tryResolveChildDirectories(inputAsURI: URI): string[] | undefined {
+ const parentDirectory = inputAsURI.path.dir.toString();
+ const cachedDirectories = this.cachedDirectories.get(parentDirectory);
+ const pendingDirectories = this.pendingResolvedDirectories.get(parentDirectory);
+ if (cachedDirectories) {
+ return cachedDirectories;
+ } else if (!pendingDirectories) {
+ this.pendingResolvedDirectories.set(parentDirectory, this.createResolutionPromise(parentDirectory));
+ }
+ return undefined;
+ }
+
+ protected async createResolutionPromise(directoryToResolve: string): Promise {
+ return this.fileService.resolve(new URI(directoryToResolve)).then(({ children }) => {
+ if (children) {
+ const childDirectories = children.filter(child => child.isDirectory)
+ .map(directory => `${directory.resource.path}/`);
+ this.cachedDirectories.set(directoryToResolve, childDirectories);
+ this.directoryResolvedEmitter.fire({ parent: directoryToResolve, children: childDirectories });
+ }
+ }).catch(e => {
+ // no-op
+ });
+ }
+}
export class LocationListRenderer extends ReactRenderer {
+ protected directoryCache: ResolvedDirectoryCache;
+ protected toDisposeOnNewCache = new DisposableCollection();
protected _drives: URI[] | undefined;
+ protected _doShowTextInput = false;
+ get doShowTextInput(): boolean {
+ return this._doShowTextInput;
+ }
+ set doShowTextInput(doShow: boolean) {
+ this._doShowTextInput = doShow;
+ if (doShow) {
+ this.initResolveDirectoryCache();
+ }
+ }
+ protected lastUniqueTextInputLocation: URI | undefined;
+ protected previousAutocompleteMatch: string;
+ protected doAttemptAutocomplete = true;
constructor(
protected readonly service: LocationService,
+ protected readonly fileService: FileService,
host?: HTMLElement
) {
super(host);
@@ -32,18 +90,113 @@ export class LocationListRenderer extends ReactRenderer {
}
render(): void {
- super.render();
+ ReactDOM.render(this.doRender(), this.host, this.doAfterRender);
+ }
+
+ protected initResolveDirectoryCache(): void {
+ this.toDisposeOnNewCache.dispose();
+ this.directoryCache = new ResolvedDirectoryCache(this.fileService);
+ this.toDisposeOnNewCache.push(this.directoryCache.onDirectoryDidResolve(({ parent, children }) => {
+ if (this.locationTextInput) {
+ const inputParent = (new URI(this.locationTextInput.value)).path.dir.toString();
+ if (inputParent === parent) {
+ this.tryRenderFirstMatch(this.locationTextInput, children);
+ }
+ }
+ }));
+ }
+
+ protected doAfterRender = (): void => {
const locationList = this.locationList;
+ const locationListTextInput = this.locationTextInput;
if (locationList) {
const currentLocation = this.service.location;
locationList.value = currentLocation ? currentLocation.toString() : '';
+ } else if (locationListTextInput) {
+ locationListTextInput.focus();
}
- }
+ };
protected readonly handleLocationChanged = (e: React.ChangeEvent) => this.onLocationChanged(e);
- protected doRender(): React.ReactNode {
+ protected readonly handleTextInputOnChange = (e: React.ChangeEvent) => this.trySuggestDirectory(e);
+ protected readonly handleTextInputKeyDown = (e: React.KeyboardEvent) => this.handleControlKeys(e);
+ protected readonly handleIconKeyDown = (e: React.KeyboardEvent) => this.toggleInputOnKeyDown(e);
+ protected readonly handleTextInputOnBlur = () => this.toggleToSelectInput();
+ protected readonly handleTextInputMouseDown = (e: React.MouseEvent) => this.toggleToTextInputOnMouseDown(e);
+
+ protected doRender(): React.ReactElement {
+ return (
+ <>
+ {this.renderInputIcon()}
+ {this.doShowTextInput
+ ? this.renderTextInput()
+ : this.renderSelectInput()
+ }
+ >
+ );
+ }
+
+ protected renderInputIcon(): React.ReactNode {
+ return (
+
+
+
+ );
+ }
+
+ protected renderTextInput(): React.ReactNode {
+ return (
+
+ );
+ }
+
+ protected renderSelectInput(): React.ReactNode {
const options = this.collectLocations().map(value => this.renderLocation(value));
- return ;
+ return (
+
+ );
+ }
+
+ protected toggleInputOnKeyDown(e: React.KeyboardEvent): void {
+ if (e.key === 'Enter') {
+ this.doShowTextInput = true;
+ this.render();
+ }
+ }
+
+ protected toggleToTextInputOnMouseDown(e: React.MouseEvent): void {
+ if (e.currentTarget.id === 'select-input') {
+ e.preventDefault();
+ this.doShowTextInput = true;
+ this.render();
+ }
+ }
+
+ protected toggleToSelectInput(): void {
+ if (this.doShowTextInput) {
+ this.doShowTextInput = false;
+ this.render();
+ }
}
/**
@@ -104,9 +257,69 @@ export class LocationListRenderer extends ReactRenderer {
if (locationList) {
const value = locationList.value;
const uri = new URI(value);
- this.service.location = uri;
+ this.trySetNewLocation(uri);
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ }
+
+ protected trySetNewLocation(newLocation: URI): void {
+ if (this.lastUniqueTextInputLocation === undefined) {
+ this.lastUniqueTextInputLocation = this.service.location;
+ }
+ // prevent consecutive repeated locations from being added to location history
+ if (this.lastUniqueTextInputLocation?.path.toString() !== newLocation.path.toString()) {
+ this.lastUniqueTextInputLocation = newLocation;
+ this.service.location = newLocation;
+ }
+ }
+
+ protected trySuggestDirectory(e: React.ChangeEvent): void {
+ if (this.doAttemptAutocomplete) {
+ const inputElement = e.currentTarget;
+ const { value } = inputElement;
+ if (value.slice(-1) !== '/') {
+ const valueAsURI = new URI(value);
+ const autocompleteDirectories = this.directoryCache.tryResolveChildDirectories(valueAsURI);
+ if (autocompleteDirectories) {
+ this.tryRenderFirstMatch(inputElement, autocompleteDirectories);
+ }
+ }
+ }
+ }
+
+ protected tryRenderFirstMatch(inputElement: HTMLInputElement, children: string[]): void {
+ const { value, selectionStart } = inputElement;
+ if (this.locationTextInput) {
+ const firstMatch = children?.find(child => child.includes(value));
+ if (firstMatch) {
+ this.locationTextInput.value = firstMatch;
+ this.locationTextInput.selectionStart = selectionStart;
+ this.locationTextInput.selectionEnd = firstMatch.length;
+ }
+ }
+ }
+
+ protected handleControlKeys(e: React.KeyboardEvent): void {
+ this.doAttemptAutocomplete = e.key !== 'Backspace';
+ if (e.key === 'Enter') {
+ const locationTextInput = this.locationTextInput;
+ if (locationTextInput) {
+ // remove extra whitespace and any trailing slashes or periods.
+ const sanitizedInput = locationTextInput.value.trim().replace(/[\/\\.]*$/, '');
+ const uri = new URI(sanitizedInput);
+ this.trySetNewLocation(uri);
+ this.toggleToSelectInput();
+ }
+ } else if (e.key === 'Escape') {
+ this.toggleToSelectInput();
+ } else if (e.key === 'Tab') {
+ e.preventDefault();
+ const textInput = this.locationTextInput;
+ if (textInput) {
+ textInput.selectionStart = textInput.value.length;
+ }
}
- e.preventDefault();
e.stopPropagation();
}
@@ -118,12 +331,31 @@ export class LocationListRenderer extends ReactRenderer {
return undefined;
}
+ get locationTextInput(): HTMLInputElement | undefined {
+ const locationTextInput = this.host.getElementsByClassName(LocationListRenderer.Styles.LOCATION_TEXT_INPUT_CLASS)[0];
+ if (locationTextInput instanceof HTMLInputElement) {
+ return locationTextInput;
+ }
+ return undefined;
+ }
+
+ dispose(): void {
+ super.dispose();
+ this.toDisposeOnNewCache.dispose();
+ }
}
export namespace LocationListRenderer {
export namespace Styles {
export const LOCATION_LIST_CLASS = 'theia-LocationList';
+ export const LOCATION_INPUT_TOGGLE_CLASS = 'theia-LocationInputToggle';
+ export const LOCATION_TEXT_INPUT_CLASS = 'theia-LocationTextInput';
+ }
+
+ export namespace Tooltips {
+ export const TOGGLE_TEXT_INPUT = 'Switch to text-based input';
+ export const TOGGLE_SELECT_INPUT = 'Switch to location list';
}
export interface Location {
diff --git a/packages/filesystem/src/browser/style/file-dialog.css b/packages/filesystem/src/browser/style/file-dialog.css
index bcb4963ef5476..d63a0d3fe5832 100644
--- a/packages/filesystem/src/browser/style/file-dialog.css
+++ b/packages/filesystem/src/browser/style/file-dialog.css
@@ -14,6 +14,14 @@
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/
+:root {
+ --theia-private-file-dialog-input-height: 21px;
+ --theia-private-location-list-panel-left: 82px;
+ --theia-private-location-list-panel-width: 417px;
+ --theia-private-navigation-panel-icon-size: 21px;
+ --theia-private-navigation-panel-line-height: 23px;
+}
+
/*
* Open and Save file dialogs
*/
@@ -56,23 +64,45 @@
/*
* Navigation panel items
*/
-
-.dialogContent .theia-NavigationBack,
-.dialogContent .theia-NavigationForward,
-.dialogContent .theia-NavigationHome {
+
+.dialogContent .theia-NavigationPanel span
+ {
position: absolute;
top: 0px;
- line-height: 23px;
+ line-height: var(--theia-private-navigation-panel-line-height);
cursor: pointer;
+ width: var(--theia-private-navigation-panel-icon-size);
+ text-align: center;
+}
+
+.dialogContent .theia-NavigationPanel span:not(.theia-mod-disabled) i.active
+{
+ transform: scale(var(--theia-toolbar-active-transform-scale));
+}
+
+.dialogContent .theia-NavigationPanel span:focus
+{
outline: none;
+ box-shadow: none;
+}
+
+.dialogContent .theia-NavigationPanel span:focus-visible
+{
+ outline-width: 1px;
+ outline-style: solid;
+ outline-offset: -1px;
+ opacity: 1 !important;
+ outline-color: var(--theia-focusBorder);
}
-.dialogContent .theia-NavigationBack:focus,
-.dialogContent .theia-NavigationForward:focus,
-.dialogContent .theia-NavigationHome:focus {
+.dialogContent .theia-NavigationBack.theia-mod-disabled:focus,
+.dialogContent .theia-NavigationForward.theia-mod-disabled:focus,
+.dialogContent .theia-NavigationHome.theia-mod-disabled:focus,
+.dialogContent .theia-NavigationUp.theia-mod-disabled:focus
+{
outline: none;
border: none;
- box-shadow: none;
+ opacity: var(--theia-mod-disabled-opacity) !important;
}
.dialogContent .theia-NavigationBack {
@@ -87,15 +117,44 @@
left: 41px;
}
+.dialogContent .theia-NavigationUp {
+ left: 61px;
+}
+
.dialogContent .theia-LocationListPanel {
position: absolute;
- left: 72px;
+ display: flex;
top: 1px;
+ left: var(--theia-private-location-list-panel-left);
+ width: var(--theia-private-location-list-panel-width);
+ height: var(--theia-private-file-dialog-input-height);
}
-.dialogContent .theia-LocationList {
- width: 427px;
- height: 21px;
+.dialogContent .theia-LocationInputToggle {
+ text-align: center;
+ left: 0;
+ width: var(--theia-private-navigation-panel-icon-size);
+ height: var(--theia-private-navigation-panel-icon-size);
+ z-index: 1;
+}
+
+.dialogContent .theia-LocationList,
+.dialogContent .theia-LocationTextInput
+{
+ box-sizing: content-box;
+ padding: unset;
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: var(--theia-private-file-dialog-input-height);
+ border: var(--theia-border-width) solid var(--theia-input-border);
+}
+
+.dialogContent .theia-LocationList,
+.dialogContent .theia-LocationTextInput
+{
+ padding-left: var(--theia-private-navigation-panel-icon-size);
+ width: calc(100% - var(--theia-private-navigation-panel-icon-size));
}
/*
@@ -117,7 +176,7 @@
.dialogContent .theia-FileTreeFiltersList {
width: 427px;
- height: 21px;
+ height: var(--theia-private-file-dialog-input-height);
}
/*