Files
Reactive-Resume/apps/web/src/components/animation/count-up.test.tsx
T
Amruth Pillai b48a9c2142 feat(web): refine motion system and simplify animated UI (#3546)
Audit every animation in the app and shared UI primitives against a
frequency-first motion bar: keyboard and high-frequency actions no longer
animate, remaining motion uses interruptible CSS transitions with shared
easing tokens, and redundant animation code is removed.

UI primitives (@reactive-resume/ui)
- Dialog, alert dialog, popover and tooltip move from tw-animate keyframes
  to Base UI data-starting/ending-style transitions; menus, popovers and
  tooltips skip motion when opened from the keyboard (data-instant).
- Dialog gains an `instant` prop; the command palette uses it.
- Accordion animates its real panel height; caret rotates instead of
  swapping icons.
- Menu backdrop blur moves onto the popup so it no longer snaps in after
  the fade; context menus and comboboxes fade only.
- Sidebar collapse uses the strong ease-out curve and snaps on Cmd+B.
- Toast, sheet, checkbox, tabs, toggle, inputs and message scroller get
  tokenised easing, correct transition properties and press feedback.
- Tabs no longer squeeze a trigger narrower than its label.
- Spinners keep spinning under prefers-reduced-motion.

Web app
- Remove the default route view transition and page-entrance slides.
- Add EASE_OUT_STRONG for Motion; replace built-in "easeOut" everywhere.
- Switch LazyMotion to domMax so layout and Reorder animations run.
- Builder: consolidate 12 section list files into one ItemsSection,
  opacity-only list rows with popLayout, instant Cmd+0, faster dock zoom,
  crossfade that no longer dips, transform-based progress bars.
- Dashboard: keep previous results while sorting/filtering, no empty-state
  flash, uncontrolled sidebar (no network round trip on collapse), calmer
  resume card tilt, no stacked hover wrappers.
- Settings: drop entrance/stagger wrappers and ActionButton.
- Agent: CSS marquee paused on hover; thread switches keep the layout.
- Homepage: fix invalid transition declarations, CSS spotlight drift,
  scroll-hiding header without a JS spring, tokenised curves.
- Theme switches change every color at once.
- Remove SSR-only useIsClient guards from the SPA.

Docs: rewrite the DESIGN.md animation section around the new tokens.
2026-09-27 17:10:42 +02:00

41 lines
1.4 KiB
TypeScript

// @vitest-environment happy-dom
import { render, waitFor } from "@testing-library/react";
import { describe, expect, it, vi } from "vitest";
import { domAnimation, LazyMotion } from "motion/react";
const reducedMotion = vi.hoisted(() => ({ value: false }));
vi.mock("motion/react", async (importOriginal) => ({
...(await importOriginal<typeof import("motion/react")>()),
useReducedMotion: () => reducedMotion.value,
}));
const { CountUp } = await import("./count-up");
describe("CountUp", () => {
it("starts at 0 before animating", () => {
reducedMotion.value = false;
const { container } = render(<CountUp to={1234} />);
expect(container.querySelector("span")?.textContent).toBe("0");
});
it("jumps to the final grouped value under reduced motion", async () => {
reducedMotion.value = true;
const { container } = render(
<LazyMotion features={domAnimation}>
<CountUp to={1234} />
</LazyMotion>,
);
await waitFor(() => expect(container.querySelector("span")?.textContent).toBe("1,234"));
});
it("forwards className and aria-hidden", () => {
reducedMotion.value = false;
const { container } = render(<CountUp to={100} className="custom-class" aria-hidden="true" />);
const span = container.querySelector("span") as HTMLSpanElement;
expect(span.className).toContain("custom-class");
expect(span.getAttribute("aria-hidden")).toBe("true");
});
});