Motion For Svelte

repository·main·Indexed 40 days ago

https://github.com/hanielu/motion-svelte

A Svelte port of Framer Motion providing powerful animation capabilities, including layout animations via createLayoutMotion, Animate Presence, and a unified animate API for elements, values, and sequences.

Tokens
23.5K
Snippets
76
Records
111
Agent score
33%

What's inside Motion For Svelte

  1. Preserve component state during HMR

    main

    HMR (Hot Module Replacement) state preservation is disabled by default in this template due to unpredictable behavior. If you have component state that must be retained during development, move that state into an external Svelte store. External stores are not replaced by HMR and will persist through updates.

    // store.ts
    // An extremely simple external store
    import { writable } from "svelte/store";
    export default writable(0);
  2. Navigate and interact with the playground

    main

    The playground provides a router-based UI for exploring Motion Svelte examples:

    • Sidebar Navigation: Click any example in the sidebar to switch views.
    • Direct URL Access: You can navigate directly to an example using the pattern /example/{example-id}.
    • Sidebar Control: Use the chevron button in the header to collapse the sidebar for more screen space.
    • Scrolling: Each example is contained within its own scrollable container, which is necessary for testing features like "In View" animations.
  3. Add new examples to the playground

    main

    To add a new Svelte component as an example in the playground, you must register it in example-registry.ts. The playground uses a central registry to automatically populate the sidebar navigation.

    1. Import your new component in example-registry.ts.
    2. Add a new object to the examples array containing a unique id, a display name, the component itself, and a category name.
    // 1. Add the import in example-registry.ts
    import MyNewExample from "./examples/my-new-example.svelte";
    
    // 2. Add it to the examples array
    {
      id: "my-new-example",
      name: "My New Example",
      component: MyNewExample,
      category: "Category Name"
    }
  4. Create a new Svelte library project

    main

    Use the sv CLI tool to scaffold a new Svelte library project. You can either initialize the project in the current directory or specify a new directory name.

    Note: Everything located in src/lib is considered part of your library's public surface, while src/routes is intended for use as a showcase or preview application.

    # create a new project in the current directory
    npx sv create
    
    # create a new project in my-app
    npx sv create my-app
  5. Set up a Svelte + TypeScript + Vite project

    main

    This template provides a minimal starting point for developing with Svelte and TypeScript using Vite. It is designed to offer a developer experience comparable to create-vite templates, focusing on HMR (Hot Module Replacement) and Intellisense.

    Use this template if you want a lightweight framework that uses its own routing solution rather than the full SvelteKit ecosystem. The project structure is designed to be similar to SvelteKit to facilitate easy migration if you decide to move to SvelteKit later.

  6. Enable Layout Animations with `createLayoutMotion`

    main

    Because Svelte lacks the lifecycle hooks used by Framer Motion (like getSnapshotBeforeUpdate), layout animations in motion-sv require a helper to track state changes and trigger layout updates.

    Use createLayoutMotion to obtain a layout controller that provides two ways to signal updates:

    1. layout.update(): Manually mark a layout change after a state update.
    2. layout.update.with(fn): A wrapper that automatically tracks the state update inside the provided function.

    When using layout components, use the layoutDependency prop to provide a reactive trigger if the element is not being remounted.

    <script lang="ts">
    	import { motion, createLayoutMotion } from "motion-sv";
    
    	let isOn = $state(false);
    	const layout = createLayoutMotion();
    
    	// Option 1: Automatic tracking via wrapper
    	const toggle = layout.update.with(() => (isOn = !isOn));
    	
    	// Option 2: Manual update
    	/*
    	function toggle() {
    	  isOn = !isOn;
    	  layout.update();
    	}
    */
    </script>
    
    <motion.button style={{ justifyContent: "flex-" + (isOn ? "start" : "end") }} onclick={toggle}>
    	<layout.div
    		style={handle}
    		layoutDependency={isOn}
    		transition={{ type: "spring", visualDuration: 0.2, bounce: 0.2 }}
    	/>
    </motion.button>
  7. Develop and build your Svelte library

    main

    After creating your project and installing dependencies (npm install, pnpm install, or yarn), use the following commands to manage your development lifecycle:

    Development

    Start the development server to work on your library and showcase app:

    npm run dev

    To automatically open the application in a new browser tab:

    npm run dev -- --open

    Building

    To package your library for distribution:

    npm run package

    To build a production version of your showcase app:

    npm run build

    To preview your production showcase build locally:

    npm run preview
    npm run dev
    npm run package
    npm run build
  8. Configure drag constraints and behavior

    main

    When using drag gestures, you can control the boundaries of movement and the physical feel of the drag using several properties.

    • dragConstraints: Defines the permitted boundaries of travel. This can be a BoundingBox or an HTMLElement (which will be measured to determine the boundaries).
    • dragElastic: Controls the elasticity/bounce when hitting constraints. If disabled, the boundary becomes much stiffer.
    • dragMomentum: A boolean determining if the element continues moving after the drag ends based on its velocity.
    • dragSnapToOrigin: If true, the element will snap back to its original position after the drag ends.
    • dragDirectionLock: If true, the drag direction (x or y) is locked once the movement exceeds a small threshold, preventing diagonal movement if only one axis is intended.
    • dragSnapToCursor: When enabled, the element's position is snapped to the pointer position at the start of the drag.
    • dragPropagation: Determines if the drag gesture should be allowed to propagate to parent elements.

    If you provide an HTMLElement to dragConstraints, you can also use onMeasureDragConstraints to intercept the measured bounding box and return a custom BoundingBox before the constraints are applied.

  9. Use drag event callbacks

    main

    The drag gesture provides several lifecycle hooks that you can trigger via props:

    • onDragStart: Fired when the drag gesture begins.
    • onDrag: Fired continuously during the movement.
    • onDragEnd: Fired when the drag gesture is released.
    • onDirectionLock: Fired when dragDirectionLock is enabled and the drag direction (x or y) is successfully determined.
    • onDragTransitionEnd: Fired after the momentum/inertia animation finishes following a drag end.
  10. Understand the MotionComponent type

    main

    The MotionComponent type defines the structure of the motion components provided by the library. It behaves differently depending on the tag provided:

    1. Standard HTML Tags: If the tag T is a valid key in DOMMotionComponents (like div, span, svg), the component will have the standard motion props associated with that HTML element.
    2. Custom Components: If T is a custom Svelte component, the MotionComponent will be a Svelte Component that accepts the custom component's own props merged with MotionProps (excluding children from the custom props to avoid conflicts).