mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-06-10 06:06:33 +00:00
fix: relaxed hover service request when scrolling
- do not render footer when scrolling - fix anchor word wrapping for long long links in the markdown - underline the link and change the cursor to pointer on hover - consider status-bar height when calculating hover top Signed-off-by: Akos Kitta <a.kitta@arduino.cc>
This commit is contained in:
parent
03355903b9
commit
5c31c93636
@ -4,7 +4,7 @@
|
|||||||
/* Adapted from https://github.com/microsoft/vscode/blob/7d9b1c37f8e5ae3772782ba3b09d827eb3fdd833/src/vs/workbench/services/hover/browser/hoverService.ts */
|
/* Adapted from https://github.com/microsoft/vscode/blob/7d9b1c37f8e5ae3772782ba3b09d827eb3fdd833/src/vs/workbench/services/hover/browser/hoverService.ts */
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--theia-hover-max-width: 200px;
|
--theia-hover-max-width: 200px; /* customized */
|
||||||
}
|
}
|
||||||
|
|
||||||
.theia-hover {
|
.theia-hover {
|
||||||
@ -29,10 +29,13 @@
|
|||||||
|
|
||||||
.theia-hover a {
|
.theia-hover a {
|
||||||
color: var(--theia-textLink-foreground);
|
color: var(--theia-textLink-foreground);
|
||||||
|
word-wrap: break-word; /* customized */
|
||||||
|
cursor: pointer; /* customized */
|
||||||
}
|
}
|
||||||
|
|
||||||
.theia-hover a:hover {
|
.theia-hover a:hover {
|
||||||
color: var(--theia-textLink-active-foreground);
|
/* color: var(--theia-textLink-active-foreground); */
|
||||||
|
text-decoration: underline; /* customized */
|
||||||
}
|
}
|
||||||
|
|
||||||
.theia-hover .hover-row .actions {
|
.theia-hover .hover-row .actions {
|
||||||
|
@ -158,6 +158,10 @@
|
|||||||
padding-top: 8px;
|
padding-top: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.component-list-item .footer.scrolling {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
.component-list-item .footer > * {
|
.component-list-item .footer > * {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
@ -144,7 +144,7 @@ export class HoverService {
|
|||||||
const documentWidth = document.body.getBoundingClientRect().width;
|
const documentWidth = document.body.getBoundingClientRect().width;
|
||||||
// document.body.getBoundingClientRect().height doesn't work as expected
|
// document.body.getBoundingClientRect().height doesn't work as expected
|
||||||
// scrollHeight will always be accurate here: https://stackoverflow.com/a/44077777
|
// scrollHeight will always be accurate here: https://stackoverflow.com/a/44077777
|
||||||
const documentHeight = document.documentElement.scrollHeight;
|
const documentHeight = document.documentElement.scrollHeight - 22; // --theia-statusBar-height: 22px;
|
||||||
position = HoverPosition.invertIfNecessary(
|
position = HoverPosition.invertIfNecessary(
|
||||||
position,
|
position,
|
||||||
targetDimensions,
|
targetDimensions,
|
||||||
|
@ -24,6 +24,7 @@ export class ComponentListItem<
|
|||||||
item,
|
item,
|
||||||
selectedVersion,
|
selectedVersion,
|
||||||
inProgress: this.state.inProgress,
|
inProgress: this.state.inProgress,
|
||||||
|
isScrolling: this.props.isScrolling,
|
||||||
install: (item) => this.install(item),
|
install: (item) => this.install(item),
|
||||||
uninstall: (item) => this.uninstall(item),
|
uninstall: (item) => this.uninstall(item),
|
||||||
onVersionChange: (version) => this.onVersionChange(version),
|
onVersionChange: (version) => this.onVersionChange(version),
|
||||||
@ -88,6 +89,7 @@ export namespace ComponentListItem {
|
|||||||
selectedVersion: Installable.Version
|
selectedVersion: Installable.Version
|
||||||
) => void;
|
) => void;
|
||||||
readonly itemRenderer: ListItemRenderer<T>;
|
readonly itemRenderer: ListItemRenderer<T>;
|
||||||
|
readonly isScrolling: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface State {
|
export interface State {
|
||||||
|
@ -2,16 +2,33 @@ import * as React from '@theia/core/shared/react';
|
|||||||
import { Virtuoso } from '@theia/core/shared/react-virtuoso';
|
import { Virtuoso } from '@theia/core/shared/react-virtuoso';
|
||||||
import { ArduinoComponent } from '../../../common/protocol/arduino-component';
|
import { ArduinoComponent } from '../../../common/protocol/arduino-component';
|
||||||
import { Installable } from '../../../common/protocol/installable';
|
import { Installable } from '../../../common/protocol/installable';
|
||||||
|
import { HoverService } from '../../theia/core/hover-service';
|
||||||
import { ComponentListItem } from './component-list-item';
|
import { ComponentListItem } from './component-list-item';
|
||||||
import { ListItemRenderer } from './list-item-renderer';
|
import { ListItemRenderer } from './list-item-renderer';
|
||||||
|
|
||||||
export class ComponentList<T extends ArduinoComponent> extends React.Component<
|
export class ComponentList<T extends ArduinoComponent> extends React.Component<
|
||||||
ComponentList.Props<T>
|
ComponentList.Props<T>,
|
||||||
|
ComponentList.State
|
||||||
> {
|
> {
|
||||||
|
constructor(props: Readonly<ComponentList.Props<T>>) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
isScrolling: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
override render(): React.ReactNode {
|
override render(): React.ReactNode {
|
||||||
return (
|
return (
|
||||||
<Virtuoso
|
<Virtuoso
|
||||||
data={this.props.items}
|
data={this.props.items}
|
||||||
|
isScrolling={(isScrolling) => {
|
||||||
|
if (this.state.isScrolling !== isScrolling) {
|
||||||
|
this.setState({ isScrolling });
|
||||||
|
if (isScrolling) {
|
||||||
|
this.props.hoverService.cancelHover();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
itemContent={(_: number, item: T) => (
|
itemContent={(_: number, item: T) => (
|
||||||
<ComponentListItem<T>
|
<ComponentListItem<T>
|
||||||
key={this.props.itemLabel(item)}
|
key={this.props.itemLabel(item)}
|
||||||
@ -21,6 +38,7 @@ export class ComponentList<T extends ArduinoComponent> extends React.Component<
|
|||||||
uninstall={this.props.uninstall}
|
uninstall={this.props.uninstall}
|
||||||
edited={this.props.edited}
|
edited={this.props.edited}
|
||||||
onItemEdit={this.props.onItemEdit}
|
onItemEdit={this.props.onItemEdit}
|
||||||
|
isScrolling={this.state.isScrolling}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@ -42,5 +60,9 @@ export namespace ComponentList {
|
|||||||
item: T,
|
item: T,
|
||||||
selectedVersion: Installable.Version
|
selectedVersion: Installable.Version
|
||||||
) => void;
|
) => void;
|
||||||
|
readonly hoverService: HoverService;
|
||||||
|
}
|
||||||
|
export interface State {
|
||||||
|
isScrolling: boolean;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ import { ListItemRenderer } from './list-item-renderer';
|
|||||||
import { ResponseServiceClient } from '../../../common/protocol';
|
import { ResponseServiceClient } from '../../../common/protocol';
|
||||||
import { nls } from '@theia/core/lib/common';
|
import { nls } from '@theia/core/lib/common';
|
||||||
import { DisposableCollection } from '@theia/core/lib/common/disposable';
|
import { DisposableCollection } from '@theia/core/lib/common/disposable';
|
||||||
|
import { HoverService } from '../../theia/core/hover-service';
|
||||||
|
|
||||||
export class FilterableListContainer<
|
export class FilterableListContainer<
|
||||||
T extends ArduinoComponent,
|
T extends ArduinoComponent,
|
||||||
@ -93,6 +94,7 @@ export class FilterableListContainer<
|
|||||||
uninstall={this.uninstall.bind(this)}
|
uninstall={this.uninstall.bind(this)}
|
||||||
edited={this.state.edited}
|
edited={this.state.edited}
|
||||||
onItemEdit={this.onItemEdit.bind(this)}
|
onItemEdit={this.onItemEdit.bind(this)}
|
||||||
|
hoverService={this.props.hoverService}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -193,6 +195,7 @@ export namespace FilterableListContainer {
|
|||||||
progressId: string;
|
progressId: string;
|
||||||
}) => Promise<void>;
|
}) => Promise<void>;
|
||||||
readonly commandService: CommandService;
|
readonly commandService: CommandService;
|
||||||
|
readonly hoverService: HoverService;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface State<T, S extends Searchable.Options> {
|
export interface State<T, S extends Searchable.Options> {
|
||||||
|
@ -114,6 +114,7 @@ interface ListItemRendererParams<T extends ArduinoComponent> {
|
|||||||
readonly item: T;
|
readonly item: T;
|
||||||
readonly selectedVersion: Installable.Version | undefined;
|
readonly selectedVersion: Installable.Version | undefined;
|
||||||
readonly inProgress?: 'installing' | 'uninstalling' | undefined;
|
readonly inProgress?: 'installing' | 'uninstalling' | undefined;
|
||||||
|
readonly isScrolling: boolean;
|
||||||
readonly install: (item: T) => Promise<void>;
|
readonly install: (item: T) => Promise<void>;
|
||||||
readonly uninstall: (item: T) => Promise<void>;
|
readonly uninstall: (item: T) => Promise<void>;
|
||||||
readonly onVersionChange: (version: Installable.Version) => void;
|
readonly onVersionChange: (version: Installable.Version) => void;
|
||||||
@ -156,15 +157,17 @@ export class ListItemRenderer<T extends ArduinoComponent> {
|
|||||||
|
|
||||||
private readonly showHover = (
|
private readonly showHover = (
|
||||||
event: React.MouseEvent<HTMLElement>,
|
event: React.MouseEvent<HTMLElement>,
|
||||||
markdown: string
|
params: ListItemRendererParams<T>
|
||||||
) => {
|
) => {
|
||||||
this.hoverService.requestHover({
|
if (!params.isScrolling) {
|
||||||
content: new MarkdownStringImpl(markdown),
|
const markdown = this.markdown(params);
|
||||||
target: event.currentTarget,
|
this.hoverService.requestHover({
|
||||||
position: 'right',
|
content: new MarkdownStringImpl(markdown),
|
||||||
});
|
target: event.currentTarget,
|
||||||
|
position: 'right',
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
renderItem(params: ListItemRendererParams<T>): React.ReactNode {
|
renderItem(params: ListItemRendererParams<T>): React.ReactNode {
|
||||||
const action = this.action(params);
|
const action = this.action(params);
|
||||||
return (
|
return (
|
||||||
@ -172,7 +175,7 @@ export class ListItemRenderer<T extends ArduinoComponent> {
|
|||||||
<Separator />
|
<Separator />
|
||||||
<div
|
<div
|
||||||
className="component-list-item noselect"
|
className="component-list-item noselect"
|
||||||
onMouseEnter={(event) => this.showHover(event, this.markdown(params))}
|
onMouseOver={(event) => this.showHover(event, params)}
|
||||||
>
|
>
|
||||||
<Header
|
<Header
|
||||||
params={params}
|
params={params}
|
||||||
@ -650,8 +653,13 @@ class Footer<T extends ArduinoComponent> extends React.Component<
|
|||||||
}>
|
}>
|
||||||
> {
|
> {
|
||||||
override render(): React.ReactNode {
|
override render(): React.ReactNode {
|
||||||
|
const { isScrolling } = this.props.params;
|
||||||
|
const className = ['footer'];
|
||||||
|
if (isScrolling) {
|
||||||
|
className.push('scrolling');
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div className="footer">
|
<div className={className.join(' ')}>
|
||||||
<SelectVersion {...this.props} />
|
<SelectVersion {...this.props} />
|
||||||
<Button {...this.props} />
|
<Button {...this.props} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -21,6 +21,7 @@ import { FilterableListContainer } from './filterable-list-container';
|
|||||||
import { ListItemRenderer } from './list-item-renderer';
|
import { ListItemRenderer } from './list-item-renderer';
|
||||||
import { NotificationCenter } from '../../notification-center';
|
import { NotificationCenter } from '../../notification-center';
|
||||||
import { StatefulWidget } from '@theia/core/lib/browser';
|
import { StatefulWidget } from '@theia/core/lib/browser';
|
||||||
|
import { HoverService } from '../../theia/core/hover-service';
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export abstract class ListWidget<
|
export abstract class ListWidget<
|
||||||
@ -38,6 +39,8 @@ export abstract class ListWidget<
|
|||||||
private readonly commandService: CommandService;
|
private readonly commandService: CommandService;
|
||||||
@inject(ResponseServiceClient)
|
@inject(ResponseServiceClient)
|
||||||
private readonly responseService: ResponseServiceClient;
|
private readonly responseService: ResponseServiceClient;
|
||||||
|
@inject(HoverService)
|
||||||
|
private readonly hoverService: HoverService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Do not touch or use it. It is for setting the focus on the `input` after the widget activation.
|
* Do not touch or use it. It is for setting the focus on the `input` after the widget activation.
|
||||||
@ -162,6 +165,7 @@ export abstract class ListWidget<
|
|||||||
commandService={this.commandService}
|
commandService={this.commandService}
|
||||||
responseService={this.responseService}
|
responseService={this.responseService}
|
||||||
onDidShow={this.onDidShowEmitter.event}
|
onDidShow={this.onDidShowEmitter.event}
|
||||||
|
hoverService={this.hoverService}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user