Coder Social home page Coder Social logo

swup / js-plugin Goto Github PK

View Code? Open in Web Editor NEW
23.0 3.0 6.0 728 KB

A swup plugin for managing animations in JS  🎸

Home Page: https://swup.js.org/plugins/js-plugin

License: MIT License

TypeScript 100.00%
swup swupjs page-transitions animation gsap animejs plugin js

js-plugin's Introduction

swup 4 is released Β πŸŽ‰Β  Check out the release notes andΒ upgradeΒ guide.


swup

npm version Bundle size npm downloads Test status License


Swup

Versatile and extensible page transition library for server-rendered websites.

Features β€’ Demos β€’ Plugins β€’ Themes β€’ Documentation β€’ Discussions

Overview

Swup adds page transitions to server-rendered websites. It manages the complete page load lifecycle and smoothly animates between the current and next page. In addition, it offers many other quality-of-life improvements like caching, smart preloading, native browser history and enhanced accessibility.

Make your site feel like a snappy single-page app β€” without any of the complexity.

Features

  • ✏️ Works out of the box with minimal markup
  • ✨ Auto-detects CSS transitions & animations for perfect timing
  • πŸ”— Updates URLs and preserves native browser history
  • πŸ“ Manages the scroll position between pages and anchor links
  • πŸš€ Uses a cache to speed up subsequent page loads
  • πŸ“‘ Offers hooks to customize and extend the page load lifecycle
  • πŸ”Œ Has a powerful plugin system and many official and third-party plugins
  • 🎨 Provides ready-to-go themes to get started quickly

Demos

Explore our interactive demos to see swup in action.

Documentation

Visit our official documentation to learn more.

Plugins

Swup is small by design. Extended features can be added via plugins:

Check out the list of official plugins and third-party integrations.

Themes

Get started quickly with one of three official themes: fade, slide, and overlay.

Examples

Take a look at the interactive demos and sites using swup for more examples.

Having trouble?

If you're having trouble implementing swup, check out the Common Issues section of the docs, look at closed issues or create a new discussion.

Want to Contribute?

We're looking for maintainers! Β  πŸ‘€

Become a sponsor on Open Collective or support development through GitHub sponsors.

This project is tested with BrowserStack.

js-plugin's People

Contributors

daun avatar dependabot[bot] avatar gmrchk avatar hirasso avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

js-plugin's Issues

[FR] Containers selector per animation

It would be great within the context of this plugin to be able to replace the content of a specific container rather than all of them. E.g. :

const transitions = [
  {
    from: '(.*)',
    to: '/tab',
    // Define one or more of the containers already defined in the main 
    // Swup instance. Only the content of this container will be loaded.
    containers: ['#tabs'], 
    out: ( next ) => {
      // Do 'out' animation on '#tabs' and replace the content of 
      // that container only. The '#swup' container is not loaded.
      next();
    }.
    in: ( next ) => {
      // Do 'in' animation.
      next();
    }
  }
]

const swup = new Swup(
  {
    containers: ["#swup", "#tabs"],
    plugins: [
      new SwupJsPlugin(transitions),
    ]
  }
);

This would allow much more powerful content manipulation and animations. For example you could load the content of just an overlay without replacing the primary content.

Occasionally, animations run while at other times, they do not. I am unable to discern how to debug the issue

Hey, thanks for implementing this library!, I have been working with this library for the past 6 months.
I'm using Astro + Swup.
On Page load animations works perfect but problems start to show up when I install jsPlugin.

// Home
    {
        from: '(.*)',
        to: '/',
        in: async (next, infos) => {
            await preloadImages('img'); // preload new images using imagesloaded.
            await takeYourTime(200); // set timeout just to be "safe"
            var tl = gsap.timeline({
                onComplete: next
            })
            tl.add(new In()) // in moves c--transition ONLY
            tl.add(new HomeTransition()) // custom transition
        },
        out: (next, infos) => {
            var tl = gsap.timeline({
                onComplete: next
            })
            if (document.getElementById('burger').className.match('b--burger-a--is-active')) {
                tl.add(letsHideTheNavbar())
            }
            tl.add(new Out()) // in moves c--transition ONLY
          
        }
    },

This is how HomeTransition Looks like

import gsap from 'gsap';
import { SplitText } from 'gsap/SplitText';
gsap.registerPlugin(SplitText)


class HomeTransition{
    constructor(){
        this.DOM = {
            // job position & developer name 
            jobposition:document.querySelector('.js--job_position'),
            developerName : document.querySelector('.js--name'),

            //stripes
            stripe:document.querySelectorAll('.c--stripes-a__item'),
            stripeArtwork:document.querySelector('.c--stripes-a__artwork'),

            //footer
            footerTitle: document.querySelector('.c--footer-a__title'),
            footerSubtitle: document.querySelector('.c--footer-a__subtitle'),
        }
        return this.init()
    }
    init(){
        console.log('test')
   
        var tl = gsap.timeline({
            defaults:{
                ease: "power2.out",
                duration:.6
            }
        })
        tl.from(new SplitText(this.DOM.jobposition, {type: "words,chars"}).chars,{
            stagger:0.014,
            opacity:0,
            y:55,
            scale:0.8,
            skewX:24,
        })
        tl.from(new SplitText(this.DOM.developerName, {type: "words,chars"}).chars,{
            stagger:0.014,
            opacity:0,
            y:55,
            scale:0.8,
            skewX:24,
        },"<25%")
        tl.from(this.DOM.stripe,{
            // duration:1,
            opacity:0,
            x:"-100%",          
            stagger: (index, target, list)=> {
                return index * 0.25;
            }
        },"<25%")
        tl.from(this.DOM.stripeArtwork,{
            opacity:0,
            scale:0.3
        })
        tl.from(this.DOM.footerTitle,{
            opacity:0,
        })
        tl.from(this.DOM.footerSubtitle,{
            opacity:0,
        },"-=.6")
        return tl
    }
}
export default HomeTransition;

It happen that sometimes/randomly splitText do not get fired.
It happens on WorkIndexTransition.js too. Can't even make a document.querySelectorAll.

https://codesandbox.io/p/github/andresclua/portfolio-frontend-2024/main?workspaceId=138605fe-a185-46bd-9550-479e93c08fe6

I just drop this codesandbox, would love some feedback.

In the transition between 2 pages, the CSS file of the second page loads late causing a very bad effect.

I used swup to do a fade transition between 2 pages. I also used the 'SwupHeadPlugin' plugin to be able to provide both pages with a different css file. So far so good, but a bad effect happens in the transition. When the second page loads, you see the page without css for a short time and then load with CSS. I tried to use the puglin js-plugin, but didn't understand how to fix this problem. HELP !!
I leave you the entire code below as a pastebin link.

first page html file:
https://pastebin.com/Xrcf7EFC

first page css file:
https://pastebin.com/i7TFhVd2

second page html file:
https://pastebin.com/aRvGMBTW

second page css file:
https://pastebin.com/p9GS4DsD

Routes plugin

Choose between animations based on custom routes defined as path regex.

Swup JS Plugin with GSAP 3 does not fire next() in onComplete

The onComplete callback with the new GSAP 3 does not work as expected with Swup page transitions. It does not fire the "next" promise function in my tests.

In a simple fade transition, the fade begins (fade out), but onComplete, no callback fired.

The last event fired is swup:pageRetrievedFromCache (I am using preload plugin as well)

I have tried keeping the same syntax (TweenMax, TweenLite, TimelineMax, etc.) - since GSAP3 supports old - in addition to trying the new syntax (gsap.timeline, gsap.to, etc.). Both resulted in the same outcome.

When I revert back to TweenMax v.2.1.3, all works as expected.

Can't seem to install JS Plugin.

What did you expect? 🧐

To run npm install @swup/js-plugin command found on the doc page and it install.

What actually happened? πŸ˜΅β€πŸ’«

Error output and the plugin not installing.
Apologies if this is a simple issue of dependencies needing to be updated, I'm not familiar with contributions.

npm WARN deprecated [email protected]: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser npm WARN deprecated @babel/[email protected]: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead. npm ERR! code Z_DATA_ERROR npm ERR! errno -3 npm ERR! zlib: incorrect data check

Swup and plugin versions πŸ“

  • swup: 4.5.0
  • Trying the latest 3.1.1

What browsers are you seeing the problem on? 🧭

No response

Relevant log output πŸ€“

No response

URL to minimal reproduction πŸ”—

Locally currently

Checked all these? πŸ“š

[Feature Request]: Make animation matching more straight forward

Describe the problem 🧐

Currently, the animations also match of either from or to matches a given route. This is pretty confusing and can lead to brittle setups.

Describe the propsed solution 😎

I'd like to follow the matching logic of fragment-plugin. Return the first animation where both from and to match the current route.

Alternatives considered πŸ€”

Leave it like it is. This would scare me away from using the plugin

How important is this feature to you? 🧭

Would make my life a lot easier

Checked all these? πŸ“š

[Bug]: Types for `from` and `to` are too restrictive

What did you expect? 🧐

I'd expect from and to to accept any value compatible to path-to-regexp:

  • string
  • string[]
  • RegExp

What actually happened? πŸ˜΅β€πŸ’«

Only string is accepted, otherwise TypeScript complains

Solution

Use the type Path exported by swup for the types.

Swup and plugin versions πŸ“

current versions

What browsers are you seeing the problem on? 🧭

No response

Relevant log output πŸ€“

No response

URL to minimal reproduction πŸ”—

n/a

Checked all these? πŸ“š

[Feature Request]: Rethink what should happen if no animation was matched

Describe the problem 🧐

Currently, the fallback for the case where a route matches no animation seems to be incoherent.

  • The readme says that a default "proceed immediately" animation will be used: "This is also the fallback animation in case no other matching animations were found."
  • The implementation seemingly uses the first defined animation instead as a fallback

Describe the propsed solution 😎

I'd like to

  • apply the default animation as mentioned in the docs as a fallback
  • warn the user that the fallback animation was used

Alternatives considered πŸ€”

I also thought about letting the user animate routes without a match in JS plugin via CSS – simple CSS animation for every page transition, except this one where I need more control. But I can imagine this would come with quite some complexity.

  • Is it possible to fallback to the default handler for animation:in:await and animation:out:await if no animation matched?
  • Is there a way to prevent CSS animations on the main transition-* class if there is a matching JS animation found?
  • .... surely some other things I can't think of right now

How important is this feature to you? 🧭

Nice to have

Checked all these? πŸ“š

Regex option does not work for me

Description of the issue

I am trying to use the regex option for routing, but it does not work correctly.
I have a routing setup that worked as follows without regex:

const options = [
  {
    // home to any other page
    from: '/',
    to: '(.*)',
    out: next => next(),
    in: next => next()
  },
  {
    // any other page to home
    from: '(.*)',
    to: '/',
    out: next => next(),
    in: next => next()
  },
];

Now, this works fine. However, I need to host my setup on a staging server, where the home page is basically in a subfolder /foo instead of /. To make it work both in my local setup as well as on the staging server I thought I can use a regex, so I did this:

const options = [
  {
    // home to any other page
    from: /\/(foo)?/, // match '/' or '/foo'
    to: '(.*)',
    out: next => next(),
    in: next => next()
  },
  {
    // any other page to home
    from: '(.*)',
    to: /\/(foo)?/, // match '/' or '/foo',
    out: next => next(),
    in: next => next()
  },
];

This works fine when I use it in my local setup, where it animates from / to any other page, but it does not work on my staging server when I want to animate from the home page at /foo to any other page. In this case it always runs the second route option where it animates back from any page to the home page.

Happens in current Firefox, Chrome and Safari browsers. I use swup 3.0.4 and the swup Js plugin 1.0.5.

Any ideas what could be going wrong? Or am I setting this up incorrectly?

Trying to get different animations for different 'from' and 'to'

Hi legends,

Not sure if this is a question for here or for GSAP.

I'm using Wordpress (latest version) and GSAP 3.3.1.

I've setup 2 different animations to be used on the site but having trouble assigning them to various routes(?).

It seems the documentation provided by SWUP, specifically JS Plugin, is using the old GSAP (v2).

Here is my code from my main index.js file. I'm also using WebPack.

domready(() => {

  function init() {

    // Initialise LazyLoad
    const projectImagesLazyLoad = new LazyLoad({
      elements_selector: ".project-image-lazy-load",
      load_delay: 300 //adjust according to use case
    })

    // Enable 'touch' class for mobile/tablet devices
    if (touchDevice) {
      document.body.classList.add('touch')
    }

    // Scroll window to top on every page load
    window.scroll({
      top: 0,
      left: 0,
      behavior: 'auto'
    })

    // Initialise global header component
    document.queryAll('[data-component="global-header"]').forEach(element => {
      new GlobalHeader({
        element
      })
    })

    // Initialise global footer component
    document.queryAll('[data-component="global-footer"]').forEach(element => {
      new GlobalFooter({
        element
      })
    })

    // Initialise PageIntroduction component
    document.queryAll('[data-component="page-introduction"]').forEach(element => {
      new PageIntroduction({
        element
      })
    })

    // Initialise InstagramFeed component
    document.queryAll('[data-component="instagram-feed"]').forEach(element => {
      new InstagramFeed({
        element
      })
    })

    // Initialise Accordions component
    document.queryAll('[data-component="accordions"]').forEach(element => {
      new Accordions({
        element
      })
    })

  }

  // animationOptions
  const animationOptions = [
    {
      from: '(.*)',
      to: '(.*)',
      out: (next) => {
        var defaultTransitionOut = gsap.timeline({repeat: 0, repeatDelay: 0, paused:true, onComplete: next})
        defaultTransitionOut.to("[data-component='default-transition']", {visibility: "visible", opacity: 0});
        defaultTransitionOut.to("[data-component='default-transition']", {duration: 0.8, opacity: 1});
        defaultTransitionOut.play()
      },
      in: (next) => {
        var defaultTransitionIn = gsap.timeline({repeat: 0, repeatDelay: 0, paused:true, onComplete: next})
        defaultTransitionIn.to("[data-component='default-transition']", {duration: 0.8, opacity: 0});
        defaultTransitionIn.to("[data-component='default-transition']", {visibility: "hidden"});
        defaultTransitionIn.play()
      }
    },
    {
      from: '(.*)',
      to: '/workshop/',
      out: (next) => {
        var mwTimelineOut = gsap.timeline({repeat: 0, repeatDelay: 0, paused:true, onComplete: next})
        mwTimelineOut.to("[data-component='mw-transition']", {opacity: 1, visibility: "visible"});
        mwTimelineOut.to("[data-component='mw-transition']", {duration: 1, x: 0, y: 0, ease: "expo.out"});
        mwTimelineOut.to("[data-component='mw-transition'] svg", {duration: 0.8, opacity: 1}, "+=0.5");
        mwTimelineOut.to("[data-component='mw-transition'] #rotate", {rotation: 180, transformOrigin: '50% 31px', ease: "expo.out", duration: 1.5}, "+=0.5");
        mwTimelineOut.play()
      },
      in: (next) => {
        var mwTimelineIn = gsap.timeline({repeat: 0, repeatDelay: 0, paused:true, onComplete: next})
        mwTimelineIn.to("[data-component='mw-transition']", {duration: 0.8, opacity: 0});
        mwTimelineIn.to("[data-component='mw-transition']", {visibility: "hidden"});
        mwTimelineIn.to("[data-component='mw-transition']", {x: "100%"});
        mwTimelineIn.play()
      }
    }
  ]

  // swupOptions
  const swupOptions = {
    plugins: [
      new SwupBodyClassPlugin(),
      new SwupDebugPlugin(),
      new SwupJsPlugin(animationOptions)
    ],
  }

  // Initialise global init
  init()

  // Initialise swup
  const swup = new Swup(swupOptions)

  // Re-initialise JS on page load
  swup.on('contentReplaced', init)

})

Basically, I want every single page to use the 1st animation. If you are going to the /workshop/ URL I want the 2nd animation to be used.

You can view the current state of development at this STAGING URL:
https://makemodels.weareduo.com.au/

There is also an issue of the initial site load (even hard refresh) where when you click on a link the transition is super jumpy and flash's.

Any help would be greatly appreciated.

Thanks

GSAP Timeline Example

Hi there,

How Would a GSAP timeline be implemented?

I tried something like this but the timeline only played on the first transition.

const transitions = [

	{
		from: '(.*)',
		to: '(.*)',
	  	out: (next) => {

			let tlPageTransitionOut = new TimelineMax({

				onComplete: next
			});
			tlPageTransitionOut
			.to(targetOne, 0.1, { /* Do Something */ }),
			tlPageTransitionOut.reverse();
			tlPageTransitionOut.play();
	  	},		  
	  	in: function(next) {

			let tlPageTransitionIn = new TimelineMax({

				onComplete: next
			});
			tlPageTransitionIn
			.to(targetOne, 0.1, { /* Do Something */ }),
			tlPageTransitionIn.reverse();
			tlPageTransitionIn.play();
			
	  	},
	}
];

Thanks for your patience! :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.