Prevent layout shift on hover in libs/board manager (#1568)

This commit is contained in:
Francesco Spissu 2022-10-25 08:58:37 +02:00 committed by GitHub
parent b8370686ec
commit 2f5afe0d9c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 9 additions and 32 deletions

View File

@ -14,37 +14,21 @@ export class ComponentListItem<
)[0]; )[0];
this.state = { this.state = {
selectedVersion: version, selectedVersion: version,
focus: false,
versionUpdate: false,
}; };
} }
} }
override componentDidUpdate(
prevProps: ComponentListItem.Props<T>,
prevState: ComponentListItem.State
): void {
if (this.state.focus !== prevState.focus) {
this.props.onFocusDidChange();
}
}
override render(): React.ReactNode { override render(): React.ReactNode {
const { item, itemRenderer } = this.props; const { item, itemRenderer } = this.props;
return ( return (
<div <>
onMouseEnter={() => this.setState({ focus: true })}
onMouseLeave={() => {
if (!this.state.versionUpdate) this.setState({ focus: false });
}}
>
{itemRenderer.renderItem( {itemRenderer.renderItem(
Object.assign(this.state, { item }), Object.assign(this.state, { item }),
this.install.bind(this), this.install.bind(this),
this.uninstall.bind(this), this.uninstall.bind(this),
this.onVersionChange.bind(this) this.onVersionChange.bind(this)
)} )}
</div> </>
); );
} }
@ -55,7 +39,6 @@ export class ComponentListItem<
)[0]; )[0];
this.setState({ this.setState({
selectedVersion: version, selectedVersion: version,
versionUpdate: false,
}); });
try { try {
await this.props.install(item, toInstall); await this.props.install(item, toInstall);
@ -71,7 +54,7 @@ export class ComponentListItem<
} }
private onVersionChange(version: Installable.Version): void { private onVersionChange(version: Installable.Version): void {
this.setState({ selectedVersion: version, versionUpdate: true }); this.setState({ selectedVersion: version });
} }
} }
@ -81,12 +64,9 @@ export namespace ComponentListItem {
readonly install: (item: T, version?: Installable.Version) => Promise<void>; readonly install: (item: T, version?: Installable.Version) => Promise<void>;
readonly uninstall: (item: T) => Promise<void>; readonly uninstall: (item: T) => Promise<void>;
readonly itemRenderer: ListItemRenderer<T>; readonly itemRenderer: ListItemRenderer<T>;
readonly onFocusDidChange: () => void;
} }
export interface State { export interface State {
selectedVersion?: Installable.Version; selectedVersion?: Installable.Version;
focus: boolean;
versionUpdate: boolean;
} }
} }

View File

@ -125,7 +125,7 @@ export class ComponentList<T extends ArduinoComponent> extends React.Component<
rowIndex={index} rowIndex={index}
parent={parent} parent={parent}
> >
{({ measure, registerChild }) => ( {({ registerChild }) => (
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
<div ref={registerChild} style={style}> <div ref={registerChild} style={style}>
@ -135,7 +135,6 @@ export class ComponentList<T extends ArduinoComponent> extends React.Component<
itemRenderer={this.props.itemRenderer} itemRenderer={this.props.itemRenderer}
install={this.props.install} install={this.props.install}
uninstall={this.props.uninstall} uninstall={this.props.uninstall}
onFocusDidChange={() => measure()}
/> />
</div> </div>
)} )}

View File

@ -28,7 +28,7 @@ export class ListItemRenderer<T extends ArduinoComponent> {
uninstall: (item: T) => Promise<void>, uninstall: (item: T) => Promise<void>,
onVersionChange: (version: Installable.Version) => void onVersionChange: (version: Installable.Version) => void
): React.ReactNode { ): React.ReactNode {
const { item, focus } = input; const { item } = input;
let nameAndAuthor: JSX.Element; let nameAndAuthor: JSX.Element;
if (item.name && item.author) { if (item.name && item.author) {
const name = <span className="name">{item.name}</span>; const name = <span className="name">{item.name}</span>;
@ -127,12 +127,10 @@ export class ListItemRenderer<T extends ArduinoComponent> {
{description} {description}
</div> </div>
<div className="info">{moreInfo}</div> <div className="info">{moreInfo}</div>
{focus && (
<div className="footer"> <div className="footer">
{versions} {versions}
{installButton} {installButton}
</div> </div>
)}
</div> </div>
); );
} }