mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-01-02 18:39:05 +01:00
set animation startTime to sync spinners for status indicators (#259)
* set animation startTime to sync spinners for status indicators * catch animationstart (hover interaction) to restart startTime. * use const --------- Co-authored-by: Evan Simkowitz <esimkowitz@users.noreply.github.com>
This commit is contained in:
parent
1a51d93a54
commit
8f64d6a589
@ -2,17 +2,19 @@ import React from "react";
|
|||||||
import { StatusIndicatorLevel } from "../../../types/types";
|
import { StatusIndicatorLevel } from "../../../types/types";
|
||||||
import cn from "classnames";
|
import cn from "classnames";
|
||||||
import { ReactComponent as SpinnerIndicator } from "../../assets/icons/spinner-indicator.svg";
|
import { ReactComponent as SpinnerIndicator } from "../../assets/icons/spinner-indicator.svg";
|
||||||
|
import { boundMethod } from "autobind-decorator";
|
||||||
|
|
||||||
interface PositionalIconProps {
|
interface PositionalIconProps {
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
className?: string;
|
className?: string;
|
||||||
onClick?: React.MouseEventHandler<HTMLDivElement>;
|
onClick?: React.MouseEventHandler<HTMLDivElement>;
|
||||||
|
divRef?: React.RefObject<HTMLDivElement>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class FrontIcon extends React.Component<PositionalIconProps> {
|
export class FrontIcon extends React.Component<PositionalIconProps> {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className={cn("front-icon", "positional-icon", this.props.className)}>
|
<div ref={this.props.divRef} className={cn("front-icon", "positional-icon", this.props.className)}>
|
||||||
<div className="positional-icon-inner">{this.props.children}</div>
|
<div className="positional-icon-inner">{this.props.children}</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -22,7 +24,11 @@ export class FrontIcon extends React.Component<PositionalIconProps> {
|
|||||||
export class CenteredIcon extends React.Component<PositionalIconProps> {
|
export class CenteredIcon extends React.Component<PositionalIconProps> {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className={cn("centered-icon", "positional-icon", this.props.className)} onClick={this.props.onClick}>
|
<div
|
||||||
|
ref={this.props.divRef}
|
||||||
|
className={cn("centered-icon", "positional-icon", this.props.className)}
|
||||||
|
onClick={this.props.onClick}
|
||||||
|
>
|
||||||
<div className="positional-icon-inner">{this.props.children}</div>
|
<div className="positional-icon-inner">{this.props.children}</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -50,6 +56,66 @@ interface StatusIndicatorProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class StatusIndicator extends React.Component<StatusIndicatorProps> {
|
export class StatusIndicator extends React.Component<StatusIndicatorProps> {
|
||||||
|
iconRef: React.RefObject<HTMLDivElement> = React.createRef();
|
||||||
|
listenerAdded: boolean = false;
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.syncSpinner();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate() {
|
||||||
|
this.syncSpinner();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount(): void {
|
||||||
|
if (this.iconRef.current != null && this.listenerAdded) {
|
||||||
|
const elem = this.iconRef.current;
|
||||||
|
const svgElem = elem.querySelector("svg");
|
||||||
|
if (svgElem != null) {
|
||||||
|
svgElem.removeEventListener("animationstart", this.handleAnimationStart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@boundMethod
|
||||||
|
handleAnimationStart(e: AnimationEvent) {
|
||||||
|
if (this.iconRef.current == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const svgElem = this.iconRef.current.querySelector("svg");
|
||||||
|
if (svgElem == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const animArr = svgElem.getAnimations();
|
||||||
|
if (animArr == null || animArr.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
animArr[0].startTime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
syncSpinner() {
|
||||||
|
if (!this.props.runningCommands) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.iconRef.current == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const elem = this.iconRef.current;
|
||||||
|
const svgElem = elem.querySelector("svg");
|
||||||
|
if (svgElem == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!this.listenerAdded) {
|
||||||
|
svgElem.addEventListener("animationstart", this.handleAnimationStart);
|
||||||
|
this.listenerAdded = true;
|
||||||
|
}
|
||||||
|
const animArr = svgElem.getAnimations();
|
||||||
|
if (animArr == null || animArr.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
animArr[0].startTime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { level, className, runningCommands } = this.props;
|
const { level, className, runningCommands } = this.props;
|
||||||
let statusIndicator = null;
|
let statusIndicator = null;
|
||||||
@ -67,7 +133,7 @@ export class StatusIndicator extends React.Component<StatusIndicatorProps> {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
statusIndicator = (
|
statusIndicator = (
|
||||||
<CenteredIcon className={cn(className, levelClass, "status-indicator")}>
|
<CenteredIcon divRef={this.iconRef} className={cn(className, levelClass, "status-indicator")}>
|
||||||
<SpinnerIndicator className={runningCommands ? "spin" : null} />
|
<SpinnerIndicator className={runningCommands ? "spin" : null} />
|
||||||
</CenteredIcon>
|
</CenteredIcon>
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user