fix(ui): align gauge animation with validation
This commit is contained in:
@@ -116,6 +116,10 @@ describe("Gauge", () => {
|
|||||||
const indicator = gauge.querySelector('[data-slot="indicator"]');
|
const indicator = gauge.querySelector('[data-slot="indicator"]');
|
||||||
const value = gauge.querySelector('[data-slot="value"]');
|
const value = gauge.querySelector('[data-slot="value"]');
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
vi.advanceTimersByTime(16);
|
||||||
|
});
|
||||||
|
|
||||||
expect(gauge).toHaveAttribute("data-animating", "");
|
expect(gauge).toHaveAttribute("data-animating", "");
|
||||||
expect(indicator).toHaveAttribute("stroke-dasharray", "0 100");
|
expect(indicator).toHaveAttribute("stroke-dasharray", "0 100");
|
||||||
expect(value).toHaveTextContent("0%");
|
expect(value).toHaveTextContent("0%");
|
||||||
|
|||||||
@@ -374,6 +374,7 @@ export const Gauge = forwardRef<HTMLDivElement, GaugeProps>(function Gauge(
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const targetPercentage = percentage ?? 0;
|
const targetPercentage = percentage ?? 0;
|
||||||
const targetValue = computedAriaValueNow ?? null;
|
const targetValue = computedAriaValueNow ?? null;
|
||||||
|
let frame = 0;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
disableMotion ||
|
disableMotion ||
|
||||||
@@ -383,17 +384,21 @@ export const Gauge = forwardRef<HTMLDivElement, GaugeProps>(function Gauge(
|
|||||||
previousPercentageRef.current === targetPercentage &&
|
previousPercentageRef.current === targetPercentage &&
|
||||||
previousValueRef.current === targetValue)
|
previousValueRef.current === targetValue)
|
||||||
) {
|
) {
|
||||||
setDisplayPercentage(targetPercentage);
|
frame = window.requestAnimationFrame(() => {
|
||||||
setDisplayValue(targetValue);
|
setDisplayPercentage(targetPercentage);
|
||||||
setIsAnimating(false);
|
setDisplayValue(targetValue);
|
||||||
previousPercentageRef.current = targetPercentage;
|
setIsAnimating(false);
|
||||||
previousValueRef.current = targetValue;
|
previousPercentageRef.current = targetPercentage;
|
||||||
|
previousValueRef.current = targetValue;
|
||||||
|
|
||||||
if (targetValue != null) {
|
if (targetValue != null) {
|
||||||
hasAnimatedRef.current = true;
|
hasAnimatedRef.current = true;
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return;
|
return () => {
|
||||||
|
window.cancelAnimationFrame(frame);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const fromPercentage = hasAnimatedRef.current ? previousPercentageRef.current : 0;
|
const fromPercentage = hasAnimatedRef.current ? previousPercentageRef.current : 0;
|
||||||
@@ -401,13 +406,8 @@ export const Gauge = forwardRef<HTMLDivElement, GaugeProps>(function Gauge(
|
|||||||
? previousValueRef.current ?? resolvedMin
|
? previousValueRef.current ?? resolvedMin
|
||||||
: resolvedMin;
|
: resolvedMin;
|
||||||
const duration = hasAnimatedRef.current ? UPDATE_SWEEP_DURATION : INITIAL_SWEEP_DURATION;
|
const duration = hasAnimatedRef.current ? UPDATE_SWEEP_DURATION : INITIAL_SWEEP_DURATION;
|
||||||
let frame = 0;
|
|
||||||
let startTime: number | null = null;
|
let startTime: number | null = null;
|
||||||
|
|
||||||
setDisplayPercentage(fromPercentage);
|
|
||||||
setDisplayValue(fromValue);
|
|
||||||
setIsAnimating(true);
|
|
||||||
|
|
||||||
const tick = (timestamp: number) => {
|
const tick = (timestamp: number) => {
|
||||||
if (startTime == null) {
|
if (startTime == null) {
|
||||||
startTime = timestamp;
|
startTime = timestamp;
|
||||||
@@ -416,6 +416,7 @@ export const Gauge = forwardRef<HTMLDivElement, GaugeProps>(function Gauge(
|
|||||||
const progress = Math.min((timestamp - startTime) / duration, 1);
|
const progress = Math.min((timestamp - startTime) / duration, 1);
|
||||||
const easedProgress = easeOutCubic(progress);
|
const easedProgress = easeOutCubic(progress);
|
||||||
|
|
||||||
|
setIsAnimating(progress < 1);
|
||||||
setDisplayPercentage(fromPercentage + (targetPercentage - fromPercentage) * easedProgress);
|
setDisplayPercentage(fromPercentage + (targetPercentage - fromPercentage) * easedProgress);
|
||||||
setDisplayValue(fromValue + (targetValue - fromValue) * easedProgress);
|
setDisplayValue(fromValue + (targetValue - fromValue) * easedProgress);
|
||||||
|
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ describe("Progress", () => {
|
|||||||
const { rerender } = render(<Progress aria-label="Reduced sync status" value={null} />);
|
const { rerender } = render(<Progress aria-label="Reduced sync status" value={null} />);
|
||||||
|
|
||||||
let progressbar = screen.getByRole("progressbar", { name: "Reduced sync status" });
|
let progressbar = screen.getByRole("progressbar", { name: "Reduced sync status" });
|
||||||
let indicator = progressbar.querySelector('[data-slot="indicator"]');
|
const indicator = progressbar.querySelector('[data-slot="indicator"]');
|
||||||
|
|
||||||
expect(progressbar).toHaveAttribute("data-reduced-motion", "");
|
expect(progressbar).toHaveAttribute("data-reduced-motion", "");
|
||||||
expect(indicator).toHaveAttribute("data-reduced-motion", "");
|
expect(indicator).toHaveAttribute("data-reduced-motion", "");
|
||||||
|
|||||||
Reference in New Issue
Block a user