Table des matières

Animations de pages

SmartCommon utilise Framer Motion pour animer les transitions entre pages. Les animations sont configurables par route.

Configuration de base

Dans la configuration du Provider :

const config = {
  pages: {
    "*": "fade" // Animation par défaut pour toutes les pages
  }
};

Animations disponibles

Animation Description Effet
fade Fondu enchaîné Opacité 0 → 1
slideLeft Glissement gauche Entrée par la droite
slideRight Glissement droite Entrée par la gauche
zoom Effet de zoom Scale 0.9 → 1

Configuration par route

Vous pouvez définir des animations différentes selon la route d'origine et de destination :

const config = {
  pages: {
    // Depuis la page d'accueil
    "/": {
      "/dashboard": "slideLeft",  // Vers dashboard: glisse à gauche
      "/settings": "slideLeft",   // Vers settings: glisse à gauche
      "*": "fade"                 // Vers autres: fondu
    },

    // Depuis le dashboard
    "/dashboard": {
      "/": "slideRight",          // Retour accueil: glisse à droite
      "/details": "slideLeft",    // Vers détails: glisse à gauche
      "*": "fade"
    },

    // Depuis les paramètres
    "/settings": {
      "/": "slideRight",
      "*": "fade"
    },

    // Pour toutes les autres pages
    "*": "fade"
  }
};

Logique de navigation

L'animation est choisie selon ce schéma :

  1. Cherche une config pour la page actuelle
  2. Si trouvée, cherche une animation pour la page précédente
  3. Si pas trouvée, utilise de la page actuelle 4. Si pas de config pour la page actuelle, utilise global

Exemple

Navigation de /dashboard vers / :

pages: {
  "/": {
    "/dashboard": "slideRight", // <- Cette animation sera utilisée
    "*": "fade"
  },
  "/dashboard": {
    "/": "slideRight",
    "*": "fade"
  }
}

La page / s'affiche avec slideRight car on vient de /dashboard.

Désactiver les animations sur desktop

Par défaut, les animations de glissement sont remplacées par fade sur desktop pour une meilleure UX :

// Dans le composant Page (comportement interne)
if (device?.type === "desktop") {
  return "fade";
}

Utiliser le composant Page

Le composant Page gère automatiquement les animations :

import { Page, Block } from '@cap-rel/smartcommon';
import { useLocation } from 'react-router-dom';

const Dashboard = () => {
  const location = useLocation();

  return (
    <Page location={location}>
      <Block>
        Contenu du dashboard
      </Block>
    </Page>
  );
};

<note important>Le prop location est requis pour que les animations fonctionnent correctement.</note>

Personnaliser les animations

Vous pouvez créer des animations personnalisées en modifiant les variants Framer Motion :

// Animations par défaut dans SmartCommon
const animations = {
  slideRight: {
    initial: { x: "50%", opacity: 0 },
    animate: { x: 0, opacity: 1, transition: { duration: 0.15, ease: "easeInOut" } },
    exit: { x: "50%", opacity: 0, transition: { duration: 0.15, ease: "easeInOut" } }
  },
  slideLeft: {
    initial: { x: "-50%", opacity: 0 },
    animate: { x: 0, opacity: 1, transition: { duration: 0.15, ease: "easeInOut" } },
    exit: { x: "-50%", opacity: 0, transition: { duration: 0.15, ease: "easeInOut" } }
  },
  fade: {
    initial: { opacity: 0 },
    animate: { opacity: 1, transition: { duration: 0.15, ease: "easeOut" } },
    exit: { opacity: 0, transition: { duration: 0.15, ease: "easeOut" } }
  },
  zoom: {
    initial: { scale: 0.9, opacity: 0 },
    animate: { scale: 1, opacity: 1 },
    exit: { scale: 0.9, opacity: 0 },
    transition: { duration: 0.2, ease: "easeOut" }
  }
};

Hook useAnimation

Pour des animations personnalisées dans vos composants :

import { useAnimation } from '@cap-rel/smartcommon';

const MyComponent = () => {
  const { start, animations, setAnimations } = useAnimation({
    fadeIn: { value: false, state: null },
    slideIn: { value: false, state: null }
  });

  useEffect(() => {
    if (start) {
      // Déclencher l'animation après le premier rendu
      setAnimations(prev => ({
        ...prev,
        fadeIn: { ...prev.fadeIn, state: 'visible' }
      }));
    }
  }, [start]);

  return (
    <motion.div
      initial={{ opacity: 0 }}
      animate={animations.fadeIn.value ? { opacity: 1 } : {}}
    >
      Contenu animé
    </motion.div>
  );
};

Animations avec Framer Motion

Pour des animations plus complexes, utilisez directement Framer Motion :

import { motion, AnimatePresence } from 'framer-motion';

const MyList = ({ items }) => (
  <AnimatePresence>
    {items.map(item => (
      <motion.div
        key={item.id}
        initial={{ opacity: 0, y: 20 }}
        animate={{ opacity: 1, y: 0 }}
        exit={{ opacity: 0, y: -20 }}
        transition={{ duration: 0.2 }}
      >
        {item.name}
      </motion.div>
    ))}
  </AnimatePresence>
);

Exemples de configurations

Application mobile classique

Navigation hiérarchique (liste → détail → sous-détail) :

pages: {
  "/": {
    "*": "slideLeft"
  },
  "/items": {
    "/": "slideRight",
    "/items/*": "slideLeft",
    "*": "fade"
  },
  "/items/*": {
    "/items": "slideRight",
    "*": "fade"
  },
  "*": "fade"
}

Application avec onglets

Navigation entre onglets sans animation de glissement :

pages: {
  "/home": { "*": "fade" },
  "/search": { "*": "fade" },
  "/profile": { "*": "fade" },
  "/settings": {
    "*": "slideLeft" // Seul settings a une animation différente
  },
  "*": "fade"
}

Désactiver toutes les animations

pages: {
  "*": "fade" // Utiliser uniquement fade (le plus discret)
}

// Ou modifier la durée à 0
// (nécessite de modifier les animations dans le code)

Voir aussi