Saltar al contenido
Logic2BUI

Buscar en la documentación

Busca componentes y documentación

Nuevo
Menú

Movimiento

Recetas de animación de entrada, salida y hover basadas en tokens, construidas con tw-animate-css sin dependencias de runtime y con una variante opcional para Framer Motion.

fade
fade-up
fade-left
scale
blur

Instalación

npx logic2b@next add motion

El motor motion incluye la primitiva <Motion> junto con los mapas de recetas y sus utilidades. Cada preset con nombre también puede instalarse por separado: motion-fade, motion-slide, motion-scale y motion-blur. Todos añaden motion de forma automática.

Uso

import { Motion } from "@/components/ui/motion"

<Motion preset="fade-up">
  <Card>…</Card>
</Motion>

<Motion> reproduce su receta de entrada una vez al montarse y después deja de interferir. Genera un div por defecto; usa asChild para animar directamente el elemento hijo sin añadir un nodo envoltorio:

<Motion preset="scale" asChild>
  <Card>…</Card>
</Motion>

Presets

Preset Efecto
fade Opacidad de 0 a 1.
fade-up Aparece mientras asciende desde abajo.
fade-down Aparece mientras desciende desde arriba.
fade-left Aparece mientras entra desde la derecha.
fade-right Aparece mientras entra desde la izquierda.
scale Aparece mientras amplía desde el 95 %.
blur Aparece mientras elimina un desenfoque de 8 px.

Temporización

La duración y el retraso son propiedades. No se genera ninguna clase arbitraria de Tailwind durante el runtime, por lo que funciona cualquier valor. delay permite escalonar una lista:

{items.map((item, i) => (
  <Motion key={item.id} preset="fade-up" duration={500} delay={i * 80}>
    <Item {...item} />
  </Motion>
))}

El valor predeterminado es una entrada ease-out de 500 ms. Sustituye la curva mediante className, como ease-in-out o ease-linear; se combina por encima del valor predeterminado.

Hover

Pasa una receta hover para añadir una interacción sobre la animación de entrada:

<Motion preset="fade" hover="lift">
  <Card>…</Card>
</Motion>
Hover Efecto
lift Asciende 4 px.
sink Desciende 2 px al presionar.
scale Crece hasta el 103 %.
glow Aumenta la sombra.

Animaciones de salida

<Motion> cubre el montaje. Cuando un elemento también deba animarse al salir —un diálogo, un panel emergente o cualquier nodo con data-[state] de Radix— usa los mapas de recetas y controla ambos estados mediante data-state:

import {
  motionEnterPresets,
  motionExitPresets,
} from "@/components/ui/motion"

// Aplicado a un nodo de contenido de Radix:
<DialogContent
  className={cn(
    "data-[state=open]:animate-in data-[state=closed]:animate-out",
    "data-[state=open]:fade-in data-[state=open]:zoom-in-95",
    "data-[state=closed]:fade-out data-[state=closed]:zoom-out-95",
  )}
/>

motionEnterPresets y motionExitPresets contienen las cadenas de clases exactas de cada preset si prefieres consultarlas a escribir cada pareja. Las utilidades motionEnter, motionExit y motionHover construyen la cadena completa —animación, temporización y protección ante movimiento reducido—.

Movimiento reducido

Todas las recetas se degradan con prefers-reduced-motion: la animación de entrada desaparece para mostrar el contenido al instante (motion-reduce:animate-none) y se desactivan las transiciones de hover (motion-reduce:transition-none). No requiere configuración adicional.

Variante para Framer Motion

Los presets anteriores usan solo CSS: no añaden coste durante el runtime y cubren los casos de entrada y hover habituales. Para física de muelle, transiciones de layout compartido o salidas en elementos que no sean de Radix, añade la variante opcional de Framer Motion. Instala framer-motion y copia este componente junto al motor CSS:

"use client"

import * as React from "react"
import { AnimatePresence, motion, type Transition } from "framer-motion"

const spring: Transition = { type: "spring", stiffness: 300, damping: 30 }

const variants = {
  fade: { hidden: { opacity: 0 }, visible: { opacity: 1 } },
  "fade-up": {
    hidden: { opacity: 0, y: 12 },
    visible: { opacity: 1, y: 0 },
  },
  scale: {
    hidden: { opacity: 0, scale: 0.95 },
    visible: { opacity: 1, scale: 1 },
  },
} as const

export function MotionSpring({
  preset = "fade-up",
  show = true,
  children,
}: {
  preset?: keyof typeof variants
  show?: boolean
  children: React.ReactNode
}) {
  return (
    <AnimatePresence>
      {show && (
        <motion.div
          initial="hidden"
          animate="visible"
          exit="hidden"
          variants={variants[preset]}
          transition={spring}
        >
          {children}
        </motion.div>
      )}
    </AnimatePresence>
  )
}

Los mismos nombres de preset y tokens aportan sensación de muelle y animaciones de salida reales cuando las necesitas, sin añadir nada al bundle cuando no.

Playground interactivo

Edita las propiedades del componente y revisa el JSX exacto antes de copiarlo. La vista previa se carga solo cuando esta sección entra en pantalla.

JSX generado
<Motion
  preset="fade-up"
  hover="lift"
  duration={500}
  delay={0}
>Animated content</Motion>

Referencia de API

Generada a partir de las exportaciones públicas de TypeScript en src/ui/motion.tsx. Las descripciones técnicas conservan el texto canónico del código fuente.

Ver JSON

MotionPreset

Tipo

Motion presets — enter/exit/hover recipes expressed as token-driven class strings on top of `tw-animate-css` (zero runtime deps). The `<Motion>` primitive plays an enter recipe once on mount; the exported maps and helpers let you drop the same recipes onto anything else (a Radix `data-[state]` element, a hand-rolled transition). Timing rides the CSS custom properties tw-animate-css reads: - default duration/easing come from the static `duration-*`/`ease-*` classes baked into `motionEnter`, - the `duration`/`delay` props override them per-instance via `--tw-animation-duration` / `--tw-animation-delay` (no arbitrary Tailwind class is generated at runtime, so it works with any value). Everything degrades under `prefers-reduced-motion`: the enter animation is dropped (content shows immediately) and hover transitions are disabled.

type MotionPreset = | "fade" | "fade-up" | "fade-down" | "fade-left" | "fade-right" | "scale" | "blur"

MotionHover

Tipo
type MotionHover = "lift" | "sink" | "scale" | "glow"

motionEnterPresets

Utilidad

Enter recipes: tw-animate-css `animate-in` sets the keyframe `from` state, the element animates to its natural rendered state.

motionExitPresets

Utilidad

Exit recipes: the mirror of each enter preset, for `animate-out` on a Radix `data-[state=closed]` element.

motionHoverPresets

Utilidad

Hover recipes: plain Tailwind transitions, no keyframes.

motionEnter

Utilidad

Build the class string for an enter recipe (plays on mount).

(preset: MotionPreset, className?: string): string

motionExit

Utilidad

Build the class string for an exit recipe (pair with `animate-out`).

(preset: MotionPreset, className?: string): string

motionHover

Utilidad

Build the class string for a hover recipe.

(hover: MotionHover, className?: string): string

MotionProps

Tipo
interface MotionProps extends React.ComponentProps<"div"> { /** Enter recipe to play on mount. Default `"fade"`. */ preset?: MotionPreset /** Optional hover recipe applied to the same element. */ hover?: MotionHover /** Enter duration in milliseconds. Overrides the 500ms default. */ duration?: number /** Enter delay in milliseconds — the knob for staggering a list. */ delay?: number /** Merge props onto the single child instead of rendering a wrapper. */ asChild?: boolean }

Motion

Componente
Props: MotionProps
PropiedadTipoObligatoriaValor predeterminadoDescripción
presetMotionPresetNo"fade"Enter recipe to play on mount. Default `"fade"`.
hoverMotionHoverNo—Optional hover recipe applied to the same element.
durationnumberNo—Enter duration in milliseconds. Overrides the 500ms default.
delaynumberNo—Enter delay in milliseconds — the knob for staggering a list.
asChildbooleanNofalseMerge props onto the single child instead of rendering a wrapper.

Contrato de accesibilidad

Comportamiento legible por máquinas y responsabilidades de quien integra motion. Los detalles normativos conservan el texto canónico del registro.

Ver JSON
Soporte
Contrato de composición
Patrón
animated semantic wrapper
Motion for React

Semántica incorporada

  • Preserves the semantics and focus behavior of the rendered child element.

Responsabilidades de integración

  • Respect prefers-reduced-motion and avoid animating focus, reading order or critical status changes.

Limitaciones conocidas

  • • Motion safety depends on the selected transition and consumer composition.