Skip to content

feat(ui): use motion for page, tab, switch and press gestures animation#2406

Open
bajrangCoder wants to merge 13 commits into
mainfrom
feat/motion-animations
Open

feat(ui): use motion for page, tab, switch and press gestures animation#2406
bajrangCoder wants to merge 13 commits into
mainfrom
feat/motion-animations

Conversation

@bajrangCoder

Copy link
Copy Markdown
Member

No description provided.

- Replaced choppy CSS transitions on page open/close with pure GPU-accelerated fade animations using motion.dev.
- Implemented a sliding active tab indicator using transform scaleX and translate3d, tracked dynamically via MutationObserver to support programmatic changes.
- Refactored switch toggle check handle to use a real DOM element with snappy spring physics.
- Added spring press scaling gestures (scale: 0.985) on list items, back arrows, and side buttons.
@bajrangCoder bajrangCoder marked this pull request as ready for review June 28, 2026 04:20
@greptile-apps

greptile-apps Bot commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR introduces the motion library to power page transitions, tab indicator animations, switch toggle springs, press/hover feedback, and a live FLIP drag-reorder animation for editor file tabs. It also adds a new Welcome tab page and refactors the editor tab drag handler with real-time preview reordering.

  • Motion animations throughout: wcPage.js gains fade-in/fade-out on connect/disconnect; tabView.js adds a spring-animated indicator tracked by MutationObserver with proper page lifecycle hooks; checkbox/index.js replaces the CSS transform transition with a Motion spring; settingsPage.js and sideButton/index.js add press-scale and hover-highlight effects.
  • Editor tab drag overhaul (editorFileTab.js): live FLIP reorder animation during drag, opacity ghosting on the picked-up tab, spring-settle of the clone on release, and automatic restoration of tab order on cancel — all using WAAPI directly.
  • CSS cleanup (settingsPage.scss): removes the background-color and transform CSS transitions that are now owned by Motion, and migrates the switch handle from ::after pseudo-element to a real .handle element.

Confidence Score: 4/5

Safe to merge for most users, but the no-animation path is broken — users who disabled animations in settings will still see all Motion-powered effects.

The core animation logic is well-structured and the tab lifecycle handling is a clear improvement. The blocking issue is that WAAPI (used by Motion and the raw element.animate() calls in editorFileTab.js) is not suppressed by body.no-animation * { animation: none !important; transition: none !important; } — these CSS rules only affect CSS transitions and @Keyframes. Every new animation in this PR will fire regardless of the user's animation preference, and the JSDoc in animateTabReorder incorrectly claims the opposite.

All files that call animate(), press(), or hover() from Motion, and editorFileTab.js where raw WAAPI element.animate() is used — specifically wcPage.js, checkbox/index.js, settingsPage.js, sideButton/index.js, tabView.js, and editorFileTab.js.

Important Files Changed

Filename Overview
src/components/WebComponents/wcPage.js Adds Motion-powered fade-in/fade-out page transitions and a press animation on the back button; transitions bypass the app's body.no-animation opt-out because WAAPI ignores CSS animation: none.
src/components/tabView.js Adds a spring-animated tab indicator using MutationObserver with proper lifecycle hooks via wc-page willconnect/willdisconnect events; touchmove is correctly registered with passive:false allowing preventDefault.
src/components/settingsPage.js Adds press/hover Motion animations to list items; hover is gated on matchMedia (hover: hover), addressing the previous review concern; animations bypass body.no-animation (same P1 as wcPage).
src/handlers/editorFileTab.js Significant refactor: adds live FLIP reorder animation during drag, opacity ghosting on the dragged tab, spring settle-clone animation on release, and position restore on cancel; JSDoc incorrectly claims WAAPI respects no-animation setting.
src/components/checkbox/index.js Replaces CSS transform transition with Motion spring animation for switch toggle knob; initial position set synchronously without animation via animateToggle=false path.
src/components/sideButton/index.js Adds a press scale animation to the side button using Motion press utility; straightforward addition with no logic issues.
src/components/settingsPage.scss Removes CSS background-color transition and CSS transform transition for switch toggle (now handled by Motion), and migrates the switch handle from ::after pseudo-element to a real .handle element; aligns with JS changes.
src/pages/welcome/welcome.js New welcome tab page with action rows and links; no Motion animations used here, logic is straightforward.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant User
    participant WCPage
    participant Motion
    participant WAAPI

    User->>WCPage: navigate to page
    WCPage->>Motion: "animate(el, {opacity:1}, {duration:0.14})"
    Motion->>WAAPI: element.animate([...])
    WAAPI-->>WCPage: animation plays (ignores body.no-animation CSS)

    User->>WCPage: press back button
    WCPage->>Motion: press(leadBtn, ...)
    Motion->>WAAPI: "element.animate([{scale:0.85}])"
    WAAPI-->>WCPage: spring scale plays

    User->>WCPage: hide page
    WCPage->>Motion: "animate(el, {opacity:0}, {duration:0.12})"
    Motion->>WAAPI: element.animate([...])
    WAAPI-->>WCPage: fade out, then remove()
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant User
    participant WCPage
    participant Motion
    participant WAAPI

    User->>WCPage: navigate to page
    WCPage->>Motion: "animate(el, {opacity:1}, {duration:0.14})"
    Motion->>WAAPI: element.animate([...])
    WAAPI-->>WCPage: animation plays (ignores body.no-animation CSS)

    User->>WCPage: press back button
    WCPage->>Motion: press(leadBtn, ...)
    Motion->>WAAPI: "element.animate([{scale:0.85}])"
    WAAPI-->>WCPage: spring scale plays

    User->>WCPage: hide page
    WCPage->>Motion: "animate(el, {opacity:0}, {duration:0.12})"
    Motion->>WAAPI: element.animate([...])
    WAAPI-->>WCPage: fade out, then remove()
Loading

Reviews (4): Last reviewed commit: "format" | Re-trigger Greptile

Comment thread src/components/tabView.js Outdated
Comment thread src/components/settingsPage.js Outdated
@bajrangCoder

This comment was marked as outdated.

@bajrangCoder

This comment was marked as outdated.

Comment thread src/components/tabView.js
@bajrangCoder

This comment was marked as outdated.

Comment on lines 97 to +116
connectedCallback() {
this.classList.remove("hide");
const isPrimary = this.classList.contains("primary");
const isNoTransition = this.classList.contains("no-transition");

if (!isPrimary) {
this.style.opacity = "0";
animate(
this,
{
opacity: 1,
},
{
duration: isNoTransition ? 0.08 : 0.14,
ease: "easeOut",
},
).then(() => {
this.style.opacity = "";
});
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Motion animations bypass body.no-animation CSS rule

main.scss disables all animations for users who opt out via body.no-animation * { animation: none !important; transition: none !important; }. That rule only suppresses CSS transitions and @keyframes — it has no effect on WAAPI (element.animate()), which is what Motion uses internally. As a result, every new animation added in this PR (page fade-in/fade-out here, spring tab indicator in tabView.js, switch toggle in checkbox/index.js, press/hover effects in settingsPage.js and sideButton/index.js) will still fire even when the user has explicitly disabled animations in Acode settings.

A minimal fix is to skip the animation when body.no-animation is active — e.g. guard each animate(…) call with if (!document.body.classList.contains('no-animation')), or pass duration: 0 in that case. The same guard is needed wherever Motion's press() and hover() utilities are called, since their callbacks invoke animate().

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

1 participant